/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation * * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Rajiv Dayal * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsRDFResource.h" #include "nsAbPalmSync.h" #include "nsIAddrBookSession.h" #include "nsAbBaseCID.h" #include "nsMsgI18N.h" #include "nsIRDFService.h" #include "nsRDFCID.h" #include "nsUnicharUtils.h" #include "nsIAbMDBCard.h" #include "nsAbCardProperty.h" #include "prdtoa.h" #include "nsMsgUtils.h" #define PREVIOUS_EXTENSION ".prev" #define kPABDirectory 2 // defined in nsDirPrefs.h #define kMAPIDirectory 3 // defined in nsDirPrefs.h #define PERSONAL_ADDRBOOK_URL "moz-abmdbdirectory://abook.mab" // defined in MozABConduitSync.h #ifdef DEBUG_bienvenu PRBool PalmDataDisplayed = PR_FALSE; void DisplayTestData(nsABCOMCardStruct * aIPCCard, PRBool IsUnicode) { if (IsUnicode) { if(aIPCCard->displayName) printf("\n Card Data For : %S:", aIPCCard->displayName); if(aIPCCard->firstName) printf("\n First Name : %S", aIPCCard->firstName); if(aIPCCard->lastName) printf("\n Last Name : %S", aIPCCard->lastName); if(aIPCCard->primaryEmail) printf("\n Email : %S", aIPCCard->primaryEmail); if(aIPCCard->workPhone) printf("\n Work Phone : %S", aIPCCard->workPhone); if(aIPCCard->homePhone) printf("\n Home Phone : %S", aIPCCard->homePhone); if(aIPCCard->faxNumber) printf("\n Fax Number : %S", aIPCCard->faxNumber); if(aIPCCard->company) printf("\n Company : %S", aIPCCard->company); if(aIPCCard->jobTitle) printf("\n Job Title : %S", aIPCCard->jobTitle); if(aIPCCard->homeAddress) printf("\n Home Address : %S", aIPCCard->homeAddress); if(aIPCCard->homeCity) printf("\n Home City : %S", aIPCCard->homeCity); if(aIPCCard->homeState) printf("\n Home State : %S", aIPCCard->homeState); printf("\n"); } else { if(aIPCCard->displayName) printf("\n Card Data For : %s:", (char *) aIPCCard->displayName); if(aIPCCard->firstName) printf("\n First Name : %s", (char *) aIPCCard->firstName); if(aIPCCard->lastName) printf("\n Last Name : %s", (char *) aIPCCard->lastName); if(aIPCCard->primaryEmail) printf("\n Email : %s", (char *) aIPCCard->primaryEmail); if(aIPCCard->workPhone) printf("\n Work Phone : %s", (char *) aIPCCard->workPhone); if(aIPCCard->homePhone) printf("\n Home Phone : %s", (char *) aIPCCard->homePhone); if(aIPCCard->faxNumber) printf("\n Fax Number : %s", (char *) aIPCCard->faxNumber); if(aIPCCard->company) printf("\n Company : %s", (char *) aIPCCard->company); if(aIPCCard->jobTitle) printf("\n Job Title : %s", (char *) aIPCCard->jobTitle); if(aIPCCard->homeAddress) printf("\n Home Address : %s", (char *) aIPCCard->homeAddress); if(aIPCCard->homeCity) printf("\n Home City : %s", (char *) aIPCCard->homeCity); if(aIPCCard->homeState) printf("\n Home State : %s", (char *) aIPCCard->homeState); printf("\n"); } } #endif nsAbPalmHotSync::nsAbPalmHotSync(PRBool aIsUnicode, PRUnichar * aAbDescUnicode, const char * aAbDesc, PRInt32 aPalmCatIndex, PRInt32 aPalmCatId) { mTotalCardCount=0; mCardForPalmCount = 0; mCardListForPalm = nsnull; mInitialized = PR_FALSE; mDBOpen = PR_FALSE; if(aIsUnicode) mAbName.Assign(aAbDescUnicode); else mAbName.AssignASCII(aAbDesc); mAbName.Trim(" "); mPalmCategoryIndex = aPalmCatIndex; mPalmCategoryId = aPalmCatId; mIsPalmDataUnicode = aIsUnicode; mNewCardCount = 0; NS_NewISupportsArray(getter_AddRefs(mNewCardsArray)); mIsNewCardForPalm = PR_FALSE; } nsAbPalmHotSync::~nsAbPalmHotSync() { // clear the nsVoidArray, don't free the stored pointers since they are freed by calling app (Conduit) mPalmRecords.Clear(); if(mDBOpen && mABDB) mABDB->Close(PR_FALSE); } // this is a utility function void nsAbPalmHotSync::ConvertAssignPalmIDAttrib(PRUint32 id, nsIAbMDBCard * card) { PRInt64 l; LL_UI2L(l, id); PRFloat64 f; LL_L2F(f, l); char buf[128]; PR_cnvtf(buf, 128, 0, f); card->SetAbDatabase(mABDB); card->SetStringAttribute(CARD_ATTRIB_PALMID,NS_ConvertASCIItoUCS2(buf).get()); } nsresult nsAbPalmHotSync::GetABInterface() { // Use GetChildNodes() call here. nsresult rv; nsCOMPtr rdfService = do_GetService (NS_RDF_CONTRACTID "/rdf-service;1", &rv); if(NS_FAILED(rv)) return E_FAIL; // Parent nsIABDirectory is "moz-abdirectory://". nsCOMPtr resource; rv = rdfService->GetResource(NS_LITERAL_CSTRING("moz-abdirectory://"), getter_AddRefs(resource)); if(NS_FAILED(rv)) return E_FAIL; nsCOMPtr directory = do_QueryInterface(resource, &rv); if(NS_FAILED(rv)) return E_FAIL; nsXPIDLCString fileName, uri, prefName; nsAutoString description; PRUint32 dirType, palmSyncTimeStamp; PRInt32 palmCategoryIndex; nsCOMPtr subDirectories; if (NS_FAILED(directory->GetChildNodes(getter_AddRefs(subDirectories))) || !subDirectories) return E_FAIL; // Check each valid addrbook. nsCOMPtr item; PRBool hasMore; while (NS_SUCCEEDED(rv = subDirectories->HasMoreElements(&hasMore)) && hasMore) { if (NS_SUCCEEDED(subDirectories->GetNext(getter_AddRefs(item)))) { directory = do_QueryInterface(item, &rv); if (NS_SUCCEEDED(rv)) { // TODO: may need to skip mailing list?? but maybe not since there's no mailing list on the top level. nsCOMPtr properties; rv = directory->GetDirectoryProperties(getter_AddRefs(properties)); if(NS_FAILED(rv)) return E_FAIL; rv = properties->GetDescription(description); if(NS_FAILED(rv)) return E_FAIL; rv = properties->GetFileName(getter_Copies(fileName)); if(NS_FAILED(rv)) return E_FAIL; rv = properties->GetURI(getter_Copies(uri)); if(NS_FAILED(rv)) return E_FAIL; rv = properties->GetDirType(&dirType); if(NS_FAILED(rv)) return E_FAIL; rv = properties->GetSyncTimeStamp(&palmSyncTimeStamp); if(NS_FAILED(rv)) return E_FAIL; rv = properties->GetCategoryId(&palmCategoryIndex); if(NS_FAILED(rv)) return E_FAIL; rv = properties->GetPrefName(getter_Copies(prefName)); // Skip/Ignore 4.X addrbooks (ie, with ".na2" extension). if (((fileName.Length() > kABFileName_PreviousSuffixLen) && strcmp(fileName.get() + fileName.Length() - kABFileName_PreviousSuffixLen, kABFileName_PreviousSuffix) == 0) || (dirType != kPABDirectory && dirType != kMAPIDirectory)) continue; // If Palm category is already assigned to AB then just check that (ie, was synced before). if((palmCategoryIndex > -1) && (mPalmCategoryIndex == palmCategoryIndex)) break; // If Palm category is not already assigned check the AB name (ie, never // synced before). Note that Palm category name is only 15 chars max. if (description.Length() > 15 && mAbName.Length() <= 15) description.Cut(15, description.Length()-15); // check for matching AB+Category, and special case personal address book // to match "Personal" category. if(description == mAbName || (prefName.Equals("ldap_2.servers.pab", nsCaseInsensitiveCStringComparator()) && mAbName.LowerCaseEqualsLiteral("personal"))) break; directory = nsnull; } } } // If not found return error. if(!directory) return NS_ERROR_FILE_NOT_FOUND; mDirectory = directory; mFileName = fileName; mUri = uri; mDescription = description; mDirType = dirType; mPalmSyncTimeStamp = palmSyncTimeStamp; return NS_OK; } nsresult nsAbPalmHotSync::Initialize() { // Use GetChildNodes() call here. if(mInitialized) return NS_OK; nsresult rv = GetABInterface(); NS_ENSURE_SUCCESS(rv, rv); mInitialized = TRUE; return NS_OK; } nsresult nsAbPalmHotSync::AddAllRecordsToAB(PRBool existingAB, PRInt32 aCount, lpnsABCOMCardStruct aPalmRecords) { NS_ENSURE_ARG_POINTER(aPalmRecords); nsresult rv; // Create the new AB dir before adding cards/records. if (existingAB) { rv = Initialize(); NS_ENSURE_SUCCESS(rv, rv); rv = OpenABDBForHotSync(PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); // lets try deleting the db out from under ourselves. nsFileSpec *abFileSpec; rv = mABDB->GetDbPath(&abFileSpec); NS_ENSURE_SUCCESS(rv, rv); mABDB->ForceClosed(); mDBOpen = PR_FALSE; mABDB = nsnull; abFileSpec->Delete(PR_FALSE); delete abFileSpec; } else { nsresult rv = NewAB(mAbName); NS_ENSURE_SUCCESS(rv, rv); rv = Initialize(); // Find the new AB and and init some vars (set mDirectory etc). NS_ENSURE_SUCCESS(rv, rv); } // open the Moz AB database rv = OpenABDBForHotSync(PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); // we are just storing the pointer array here not record arrays for (PRInt32 i=0; i < aCount; i++) mPalmRecords.AppendElement(&aPalmRecords[i]); // new DB here so no need to backup rv = UpdateMozABWithPalmRecords(); rv = mABDB->Close(NS_SUCCEEDED(rv)); if(NS_SUCCEEDED(rv)) { mDBOpen = PR_FALSE; PRUint32 modTimeInSec; PRTime2Seconds(PR_Now(), &modTimeInSec); rv = UpdateABInfo(modTimeInSec, mPalmCategoryIndex); } else { // get back the previous file rv = mABDB->ForceClosed(); if(NS_SUCCEEDED(rv)) { nsCAutoString leafName; mABFile->GetNativeLeafName(leafName); PRBool bExists=PR_FALSE; mPreviousABFile->Exists(&bExists); if(bExists) { nsCOMPtr parent; rv = mABFile->GetParent(getter_AddRefs(parent)); if (NS_SUCCEEDED(rv)) { mABFile->Remove(PR_FALSE); mPreviousABFile->CopyToNative(parent, leafName); } } mDBOpen = PR_FALSE; } } return rv; } nsresult nsAbPalmHotSync::GetAllCards(PRInt32 * aCount, lpnsABCOMCardStruct * aCardList) { NS_ENSURE_ARG_POINTER(aCount); NS_ENSURE_ARG_POINTER(aCardList); if(!mInitialized) return NS_ERROR_NOT_INITIALIZED; // open the Moz AB database nsresult rv = OpenABDBForHotSync(PR_FALSE); if(NS_FAILED(rv)) return rv; // create the list to be sent back to Palm mABDB->GetCardCount(&mTotalCardCount); *aCount = mTotalCardCount; if(!mTotalCardCount) { mABDB->Close(PR_FALSE); return NS_OK; } mCardListForPalm = (lpnsABCOMCardStruct) CoTaskMemAlloc(sizeof(nsABCOMCardStruct) * mTotalCardCount); if(!mCardListForPalm) { mABDB->Close(PR_FALSE); return NS_ERROR_OUT_OF_MEMORY; } nsCOMPtr cardsEnumerator; rv = mABDB->EnumerateCards(mDirectory, getter_AddRefs(cardsEnumerator)); if (NS_FAILED(rv) || !cardsEnumerator) { mABDB->Close(PR_FALSE); return rv; } nsCOMPtr item; nsCOMPtr card; for (rv = cardsEnumerator->First(); NS_SUCCEEDED(rv); rv = cardsEnumerator->Next()) { rv = cardsEnumerator->CurrentItem(getter_AddRefs(item)); if (NS_FAILED(rv)) continue; card = do_QueryInterface(item, &rv); if (NS_FAILED(rv)) // can this be anything but a card? continue; PRBool isMailingList=PR_FALSE; rv = card->GetIsMailList(&isMailingList); if (NS_FAILED(rv) || isMailingList) // if mailing list go to cards continue; nsAbIPCCard ipcCard(card); ipcCard.SetStatus(ATTR_NEW); rv = AddToListForPalm(ipcCard); if(NS_FAILED(rv)) break; mNewCardsArray->AppendElement(card); mNewCardCount++; } *aCount = mCardForPalmCount; *aCardList = mCardListForPalm; // Don't close the DB yet, it will be closed when Done is called return NS_OK; } nsresult nsAbPalmHotSync::DoSyncAndGetUpdatedCards(PRInt32 aPalmCount, lpnsABCOMCardStruct aPalmRecords, PRInt32 * aMozCount, lpnsABCOMCardStruct * aMozCards) { NS_ENSURE_ARG_POINTER(aPalmRecords); NS_ENSURE_ARG_POINTER(aMozCount); NS_ENSURE_ARG_POINTER(aMozCards); if(!mInitialized) return NS_ERROR_NOT_INITIALIZED; // open the Moz AB database nsresult rv = OpenABDBForHotSync(PR_FALSE); if(NS_FAILED(rv)) return rv; // we are just storing the pointer array here, not record arrays for (PRInt32 i=0; i < aPalmCount; i++) { mPalmRecords.AppendElement(&aPalmRecords[i]); #ifdef DEBUG_bienvenu DisplayTestData(&aPalmRecords[i],PR_FALSE); #endif } // create the list to be sent back to Palm mABDB->GetCardCount(&mTotalCardCount); PRUint32 deletedCardCount=0; mABDB->GetDeletedCardCount(&deletedCardCount); mTotalCardCount += deletedCardCount; if(mTotalCardCount) { mCardListForPalm = (lpnsABCOMCardStruct) CoTaskMemAlloc(sizeof(nsABCOMCardStruct) * mTotalCardCount); if(!mCardListForPalm) { mABDB->Close(PR_FALSE); return NS_ERROR_OUT_OF_MEMORY; } } // initialize the flag for any new Moz cards to be added to Palm mIsNewCardForPalm = PR_FALSE; // deal with new / modified or first time sync rv = LoadNewModifiedCardsSinceLastSync(); if(NS_SUCCEEDED(rv)) // deal with deleted rv = LoadDeletedCardsSinceLastSync(); if(NS_SUCCEEDED(rv)) // first backup the existing DB as Previous rv = KeepCurrentStateAsPrevious(); if(NS_SUCCEEDED(rv)) // update local DB for sync rv = UpdateMozABWithPalmRecords(); // if there are no new cards to be added in Palm close DB // else wait for Done to be called. if(!mIsNewCardForPalm) { rv = mABDB->Close(NS_SUCCEEDED(rv) && mPalmRecords.Count()); if(NS_SUCCEEDED(rv)) { mDBOpen = PR_FALSE; PRUint32 modTimeInSec; PRTime2Seconds(PR_Now(), &modTimeInSec); rv = UpdateABInfo(modTimeInSec, mPalmCategoryIndex); } else { // get back the previous file rv = mABDB->ForceClosed(); if(NS_SUCCEEDED(rv)) { nsCAutoString leafName; mABFile->GetNativeLeafName(leafName); PRBool bExists=PR_FALSE; mPreviousABFile->Exists(&bExists); if(bExists) { nsCOMPtr parent; rv = mABFile->GetParent(getter_AddRefs(parent)); if (NS_SUCCEEDED(rv)) { mABFile->Remove(PR_FALSE); mPreviousABFile->CopyToNative(parent, leafName); } } mDBOpen = PR_FALSE; } } } *aMozCount = mCardForPalmCount; *aMozCards = mCardListForPalm; return rv; } // this takes care of the cases when the state is deleted nsresult nsAbPalmHotSync::LoadDeletedCardsSinceLastSync() { if(!mDBOpen || !mABDB || !mInitialized) return NS_ERROR_NOT_INITIALIZED; nsISupportsArray * deletedCardArray; PRUint32 deletedCardCount; nsresult rv = mABDB->GetDeletedCardList(&deletedCardCount, &deletedCardArray); if(NS_FAILED(rv)) return rv; for(PRUint32 i=0; i < deletedCardCount; i++) { nsCOMPtr card; rv = deletedCardArray->QueryElementAt(i, NS_GET_IID(nsIAbCard), getter_AddRefs(card)); if (NS_FAILED(rv)) // can this be anything but a card? continue; PRBool isMailingList=PR_FALSE; rv = card->GetIsMailList(&isMailingList); if (NS_FAILED(rv) || isMailingList) continue; PRUint32 lastModifiedDate = 0; rv = card->GetLastModifiedDate(&lastModifiedDate); if (NS_FAILED(rv) || !lastModifiedDate) continue; if(lastModifiedDate > mPalmSyncTimeStamp) { nsAbIPCCard ipcCard(card); // check in the list of Palm records for(PRInt32 i=mPalmRecords.Count()-1; i >=0; i--) { nsABCOMCardStruct * palmRec = (nsABCOMCardStruct *) mPalmRecords.ElementAt(i); // if same record exists in palm list, donot delete it from Palm if(ipcCard.Same(palmRec, mIsPalmDataUnicode)) continue; } ipcCard.SetStatus(ATTR_DELETED); rv = AddToListForPalm(ipcCard); if(NS_FAILED(rv)) break; } } return rv; } nsresult nsAbPalmHotSync::LoadNewModifiedCardsSinceLastSync() { if(!mDBOpen || !mABDB || !mInitialized) return NS_ERROR_NOT_INITIALIZED; nsCOMPtr cardsEnumerator; nsresult rv = mABDB->EnumerateCards(mDirectory, getter_AddRefs(cardsEnumerator)); if (NS_FAILED(rv) || !cardsEnumerator) return NS_ERROR_NOT_AVAILABLE; // no cards available // create the list of cards to be sent to Palm nsCOMPtr item; nsCOMPtr card; for (rv = cardsEnumerator->First(); NS_SUCCEEDED(rv); rv = cardsEnumerator->Next()) { rv = cardsEnumerator->CurrentItem(getter_AddRefs(item)); if (NS_FAILED(rv)) return rv; card = do_QueryInterface(item, &rv); if (NS_FAILED(rv)) // can this be anything but a card? continue; PRBool isMailingList=PR_FALSE; rv = card->GetIsMailList(&isMailingList); if (NS_FAILED(rv) || isMailingList) // if mailing list go to cards continue; PRUint32 lastModifiedDate = 0; rv = card->GetLastModifiedDate(&lastModifiedDate); if (NS_FAILED(rv)) continue; if(lastModifiedDate > mPalmSyncTimeStamp // take care of modified || !lastModifiedDate || !mPalmSyncTimeStamp) { // take care of new or never before sync //create nsAbIPCCard and assign its status based on lastModifiedDate nsAbIPCCard ipcCard(card); ipcCard.AddRef(); // someone needs a reference to this, since we // pass it around as an interface pointer ipcCard.SetStatus((lastModifiedDate) ? ATTR_MODIFIED : ATTR_NEW); // Check with the palm list (merging is done if required) if (CardExistsInPalmList(&ipcCard)) continue; rv = AddToListForPalm(ipcCard); if(NS_FAILED(rv)) break; if(ipcCard.GetStatus() == ATTR_NEW) { mNewCardsArray->AppendElement(card); mNewCardCount++; mIsNewCardForPalm = PR_TRUE; } } } return NS_OK; } // this take care of the all cases when the state is either modified or new PRBool nsAbPalmHotSync::CardExistsInPalmList(nsAbIPCCard * aIPCCard) { NS_ENSURE_ARG_POINTER(aIPCCard); if(!mInitialized) return PR_FALSE; PRBool exists = PR_FALSE; for(PRInt32 i=mPalmRecords.Count()-1; i >=0; i--) { nsABCOMCardStruct * palmRec = (nsABCOMCardStruct *) mPalmRecords.ElementAt(i); // if same record is in palm list also if(aIPCCard->Same(palmRec, mIsPalmDataUnicode)) { // if the state deleted on both sides no need to do anything if ((palmRec->dwStatus & ATTR_DELETED || palmRec->dwStatus & ATTR_ARCHIVED) && (aIPCCard->GetStatus() == ATTR_DELETED)) { mPalmRecords.RemoveElementAt(i); return PR_TRUE; } // if deleted on Palm and added or modified on Moz, don't delete on Moz if ( (palmRec->dwStatus & ATTR_DELETED || palmRec->dwStatus & ATTR_ARCHIVED) && ((aIPCCard->GetStatus() == ATTR_NEW) || (aIPCCard->GetStatus() == ATTR_MODIFIED)) ) { mPalmRecords.RemoveElementAt(i); return PR_FALSE; } // set the palm record ID in the card if not already set if(!aIPCCard->GetRecordId()) { ConvertAssignPalmIDAttrib(palmRec->dwRecordId, aIPCCard); mABDB->EditCard(aIPCCard, PR_FALSE); aIPCCard->SetRecordId(palmRec->dwRecordId); } // if deleted in Moz and added or modified on Palm, don't delete on Palm if ( (aIPCCard->GetStatus() == ATTR_DELETED) && ((palmRec->dwStatus == ATTR_NEW) ||(palmRec->dwStatus == ATTR_MODIFIED)) ) return PR_TRUE; // for rest of the cases with state as either mod or new: nsStringArray diffAttrs; PRBool fieldsMatch = PR_FALSE; if(mIsPalmDataUnicode) fieldsMatch = aIPCCard->Equals(palmRec, diffAttrs); else fieldsMatch = aIPCCard->EqualsAfterUnicodeConversion(palmRec, diffAttrs); // if fields match, no need to keep it for sync if(fieldsMatch) { exists = PR_TRUE; // since the fields match, no need to update Moz AB with palm record mPalmRecords.RemoveElementAt(i); } else { // we add an additional record on both sides alike Palm Desktop sync palmRec->dwStatus = ATTR_NONE; aIPCCard->SetStatus(ATTR_NEW); exists = PR_FALSE; } // since we found the same record in palm sync list // no need to go thru the rest of the mPalmRecords list break; } } return exists; } // utility function nsresult nsAbPalmHotSync::AddToListForPalm(nsAbIPCCard & ipcCard) { // this should never happen but check for crossing array index if(mCardForPalmCount >= mTotalCardCount) return NS_ERROR_UNEXPECTED; nsresult rv = ipcCard.GetABCOMCardStruct(mIsPalmDataUnicode, &mCardListForPalm[mCardForPalmCount]); if(NS_SUCCEEDED(rv)) { mCardListForPalm[mCardForPalmCount].dwCategoryId = mPalmCategoryId; mCardForPalmCount++; } return rv; } nsresult nsAbPalmHotSync::OpenABDBForHotSync(PRBool aCreate) { if(!mInitialized) return NS_ERROR_NOT_INITIALIZED; // if already open if(mDBOpen && mABDB && mDirectory) return NS_OK; if(mFileName.IsEmpty()) return NS_ERROR_FILE_INVALID_PATH; nsresult rv; nsCOMPtr abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv); if(NS_FAILED(rv)) return rv; rv = abSession->GetUserProfileDirectory(getter_AddRefs(mABFile)); if(NS_FAILED(rv)) return rv; mABFile->AppendNative(mFileName); nsCOMPtr addrDBFactory = do_GetService(NS_ADDRDATABASE_CONTRACTID, &rv); if(NS_FAILED(rv)) { return rv; } rv = addrDBFactory->Open(mABFile, aCreate, PR_TRUE, getter_AddRefs(mABDB)); NS_ENSURE_SUCCESS(rv, rv); mDBOpen = PR_TRUE; // Moz AB DB is now Open return rv; } nsresult nsAbPalmHotSync::KeepCurrentStateAsPrevious() { if(!mInitialized) return NS_ERROR_NOT_INITIALIZED; nsresult rv = NS_OK; nsCAutoString previousLeafName(mFileName); previousLeafName += PREVIOUS_EXTENSION; if(!mPreviousABFile) { nsCOMPtr abSession = do_GetService(NS_ADDRBOOKSESSION_CONTRACTID, &rv); if(NS_FAILED(rv)) return rv; rv = abSession->GetUserProfileDirectory(getter_AddRefs(mPreviousABFile)); if(NS_SUCCEEDED(rv)) { mPreviousABFile->AppendNative(previousLeafName); if(NS_FAILED(rv)) return rv; } } PRBool bExists=PR_FALSE; mABFile->Exists(&bExists); if(bExists) { mPreviousABFile->Exists(&bExists); if(bExists) rv = mPreviousABFile->Remove(PR_FALSE); nsCOMPtr parent; rv = mABFile->GetParent(getter_AddRefs(parent)); if (NS_SUCCEEDED(rv)) rv = mABFile->CopyToNative(parent, previousLeafName); } return rv; } nsresult nsAbPalmHotSync::UpdateMozABWithPalmRecords() { if(!mInitialized || !mABDB || !mDBOpen) return NS_ERROR_NOT_INITIALIZED; nsresult rv = NS_OK; for(PRInt32 i=mPalmRecords.Count()-1; i >=0; i--) { nsABCOMCardStruct * palmRec = (nsABCOMCardStruct *)mPalmRecords.ElementAt(i); nsAbIPCCard ipcCard(palmRec, PR_FALSE); char recordIDBuf[128]; PRInt64 l; LL_UI2L(l, palmRec->dwRecordId); PRFloat64 f; LL_L2F(f, l); PR_cnvtf(recordIDBuf, 128, 0, f); // if the card already exists nsCOMPtr existingCard; rv = mABDB->GetCardFromAttribute(nsnull, CARD_ATTRIB_PALMID, recordIDBuf, PR_FALSE, getter_AddRefs(existingCard)); if (!existingCard) { rv = mABDB->GetCardFromAttribute(nsnull, CARD_ATTRIB_DISPLAY, (const char *) palmRec->displayName, PR_FALSE, getter_AddRefs(existingCard)); // if card with this display name exists, just continue; But, we should make sure // it's associated with the palm card going forward, so set the palmid. if (NS_SUCCEEDED(rv) && existingCard) { nsCOMPtr dbCard = do_QueryInterface(existingCard); dbCard->SetStringAttribute(CARD_ATTRIB_PALMID, NS_ConvertASCIItoUCS2(recordIDBuf).get()); continue; } } if(NS_SUCCEEDED(rv) && existingCard) { // Archived is the same as deleted in palm. if(palmRec->dwStatus & ATTR_DELETED || palmRec->dwStatus & ATTR_ARCHIVED) { mABDB->DeleteCard(existingCard, PR_FALSE); continue; } if(palmRec->dwStatus & ATTR_NEW) continue; if(palmRec->dwStatus & ATTR_MODIFIED) { PRBool isEqual=PR_FALSE; ipcCard.Equals(existingCard, &isEqual); if(isEqual) continue; else { existingCard->Copy(&ipcCard); rv = mABDB->EditCard(existingCard, PR_FALSE); continue; } } } nsCOMPtr dbCard; dbCard = do_CreateInstance(NS_ABMDBCARD_CONTRACTID, &rv); if(NS_FAILED(rv)) continue; nsCOMPtr newCard; newCard = do_QueryInterface(dbCard, &rv); if(NS_FAILED(rv)) continue; rv = newCard->Copy(&ipcCard); if(NS_FAILED(rv)) continue; // if the card does not exist if((ipcCard.GetStatus() == ATTR_NEW) ||(ipcCard.GetStatus() == ATTR_MODIFIED) || (ipcCard.GetStatus() == ATTR_NONE)) { PRUint32 modTimeInSec; PRTime2Seconds(PR_Now(), &modTimeInSec); ipcCard.SetLastModifiedDate(modTimeInSec); rv = mABDB->CreateNewCardAndAddToDB(newCard, PR_FALSE); if(NS_SUCCEEDED(rv)) { // now set the attribute for the PalmRecID in the card in the DB dbCard->SetAbDatabase(mABDB); dbCard->SetStringAttribute(CARD_ATTRIB_PALMID, NS_ConvertASCIItoUCS2(recordIDBuf).get()); newCard = do_QueryInterface(dbCard, &rv); if(NS_SUCCEEDED(rv)) rv = mABDB->EditCard(newCard, PR_FALSE); } } } return rv; } nsresult nsAbPalmHotSync::Done(PRBool aSuccess, PRInt32 aPalmCatIndex, PRUint32 aPalmRecIDListCount, unsigned long * aPalmRecordIDList) { if(!mInitialized) return NS_ERROR_NOT_INITIALIZED; nsresult rv=NS_ERROR_UNEXPECTED; if(aPalmRecIDListCount == mNewCardCount) { for(PRUint32 i=0; i dbCard; rv = mNewCardsArray->QueryElementAt(i, NS_GET_IID(nsIAbMDBCard), getter_AddRefs(dbCard)); if(NS_SUCCEEDED(rv) && dbCard) { ConvertAssignPalmIDAttrib(aPalmRecordIDList[i], dbCard); nsCOMPtr newCard; newCard = do_QueryInterface(dbCard, &rv); if(NS_SUCCEEDED(rv)) mABDB->EditCard(newCard, PR_FALSE); } } } if(mABDB && mDBOpen) { if(aSuccess) { rv = mABDB->Close(PR_TRUE); if(NS_SUCCEEDED(rv)) { mDBOpen = PR_FALSE; PRUint32 modTimeInSec; PRTime2Seconds(PR_Now(), &modTimeInSec); rv = UpdateABInfo(modTimeInSec, aPalmCatIndex); } } if(NS_FAILED(rv) || !aSuccess) { // get back the previous file rv = mABDB->ForceClosed(); if(NS_SUCCEEDED(rv)) { nsCAutoString leafName; mABFile->GetNativeLeafName(leafName); PRBool bExists=PR_FALSE; mPreviousABFile->Exists(&bExists); if(bExists) { nsCOMPtr parent; rv = mABFile->GetParent(getter_AddRefs(parent)); if (NS_SUCCEEDED(rv)) { mABFile->Remove(PR_FALSE); mPreviousABFile->CopyToNative(parent, leafName); } } mDBOpen = PR_FALSE; } } } return rv; } nsresult nsAbPalmHotSync::UpdateSyncInfo(long aCategoryIndex) { // aCategoryIndex = -1 means that callers want to reset the mod time as well. mDBOpen = PR_FALSE; PRUint32 modTimeInSec; PRTime2Seconds(PR_Now(), &modTimeInSec); if (aCategoryIndex >= 0) return(UpdateABInfo(modTimeInSec, aCategoryIndex)); else return(UpdateABInfo(0, aCategoryIndex)); // Reset mod time. } nsresult nsAbPalmHotSync::DeleteAB(long aCategoryIndex, const char * aABUrl) { nsresult rv; nsCOMPtr parentArray(do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr selectedArray(do_CreateInstance(NS_SUPPORTSARRAY_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr rdfService = do_GetService (NS_RDF_CONTRACTID "/rdf-service;1", &rv); NS_ENSURE_SUCCESS(rv, rv); // Parent nsIABDirectory: like "moz-abdirectory://". nsCOMPtr resource; rv = rdfService->GetResource(NS_LITERAL_CSTRING("moz-abdirectory://"), getter_AddRefs(resource)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr parentDirectory = do_QueryInterface(resource, &rv); NS_ENSURE_SUCCESS(rv, rv); parentArray->AppendElement(parentDirectory); // Selected folder nsIABDirectory: like "moz-abmdbdirectory://abook-1.mab" nsCOMPtr childResource; rv = rdfService->GetResource(nsDependentCString(aABUrl), getter_AddRefs(childResource)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr selectedDirectory = do_QueryInterface(childResource, &rv); NS_ENSURE_SUCCESS(rv, rv); selectedArray->AppendElement(selectedDirectory); nsCOMPtr ds; rv = rdfService->GetDataSource("rdf:addressdirectory", getter_AddRefs(ds)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr ab = do_CreateInstance(NS_ADDRESSBOOK_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); return(ab->DeleteAddressBooks(ds, parentArray, selectedArray)); } nsresult nsAbPalmHotSync::RenameAB(long aCategoryIndex, const char * aABUrl) { // Fill in property info and call ModifyAB(). nsresult rv; nsCOMPtr properties(do_CreateInstance(NS_ABDIRECTORYPROPERTIES_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv,rv); // For modify to work, we only need to set description, uri and dir type. rv = properties->SetDescription(mAbName); NS_ENSURE_SUCCESS(rv,rv); rv = properties->SetURI(aABUrl); NS_ENSURE_SUCCESS(rv,rv); rv = properties->SetDirType(kPABDirectory); // pab dir type for PalmSync NS_ENSURE_SUCCESS(rv,rv); rv = properties->SetCategoryId(aCategoryIndex); NS_ENSURE_SUCCESS(rv,rv); PRUint32 modTimeInSec; PRTime2Seconds(PR_Now(), &modTimeInSec); rv = properties->SetSyncTimeStamp(modTimeInSec); NS_ENSURE_SUCCESS(rv,rv); return(ModifyAB(aABUrl, properties)); } nsresult nsAbPalmHotSync::NewAB(const nsString& aAbName) { nsresult rv; nsCOMPtr ab = do_CreateInstance(NS_ADDRESSBOOK_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr properties = do_CreateInstance(NS_ABDIRECTORYPROPERTIES_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); properties->SetDirType(kPABDirectory); properties->SetDescription(aAbName); return(ab->NewAddressBook(properties)); } nsresult nsAbPalmHotSync::UpdateABInfo(PRUint32 aModTime, PRInt32 aCategoryIndex) { // Fill in property info and call ModifyAB(). nsresult rv; nsCOMPtr properties(do_CreateInstance(NS_ABDIRECTORYPROPERTIES_CONTRACTID, &rv)); NS_ENSURE_SUCCESS(rv,rv); // For modify to work, we only need to set description, uri and // dir type. Then add mod time and category id we want to modify. rv = properties->SetDescription(mDescription); NS_ENSURE_SUCCESS(rv,rv); rv = properties->SetURI(mUri.get()); NS_ENSURE_SUCCESS(rv,rv); rv = properties->SetDirType(mDirType); NS_ENSURE_SUCCESS(rv,rv); rv = properties->SetCategoryId(aCategoryIndex); NS_ENSURE_SUCCESS(rv,rv); rv = properties->SetSyncTimeStamp(aModTime); NS_ENSURE_SUCCESS(rv,rv); return(ModifyAB(mUri.get(), properties)); } nsresult nsAbPalmHotSync::ModifyAB(const char * aABUrl, nsIAbDirectoryProperties *aProperties) { nsresult rv; nsCOMPtr rdfService = do_GetService (NS_RDF_CONTRACTID "/rdf-service;1", &rv); NS_ENSURE_SUCCESS(rv, rv); // Parent nsIABDirectory: like "moz-abdirectory://". nsCOMPtr resource; rv = rdfService->GetResource(NS_LITERAL_CSTRING("moz-abdirectory://"), getter_AddRefs(resource)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr parentDirectory = do_QueryInterface(resource, &rv); NS_ENSURE_SUCCESS(rv, rv); // Selected folder nsIABDirectory: like "moz-abmdbdirectory://abook-1.mab" nsCOMPtr childResource; rv = rdfService->GetResource(nsDependentCString(aABUrl), getter_AddRefs(childResource)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr selectedDirectory = do_QueryInterface(childResource, &rv); NS_ENSURE_SUCCESS(rv, rv); // RDF data source for addrbook nsCOMPtr ds; rv = rdfService->GetDataSource("rdf:addressdirectory", getter_AddRefs(ds)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr ab = do_CreateInstance(NS_ADDRESSBOOK_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); return(ab->ModifyAddressBook(ds, parentDirectory, selectedDirectory, aProperties)); }