You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1049 lines
26 KiB
1049 lines
26 KiB
4 years ago
|
/*
|
||
|
* sync.c: Implement generic synchronization algorithm
|
||
|
*
|
||
|
* Documentation of the sync cases is at:
|
||
|
* http://www.palmos.com/dev/tech/docs/conduits/win/Intro_CondBasics.html#928692
|
||
|
*
|
||
|
* Copyright (c) 2000-2001, Ximian Inc.
|
||
|
*
|
||
|
* Author: JP Rosevear <jpr@helixcode.com>
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or modify it
|
||
|
* under the terms of the GNU Library General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or (at
|
||
|
* your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful, but
|
||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
|
||
|
* General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Library General Public License
|
||
|
* along with this library; if not, write to the Free Software Foundation,
|
||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "pi-dlp.h"
|
||
|
#include "pi-sync.h"
|
||
|
|
||
|
typedef enum {
|
||
|
PILOT,
|
||
|
DESKTOP,
|
||
|
BOTH
|
||
|
} RecordModifier;
|
||
|
|
||
|
typedef struct _RecordQueueList RecordQueueList;
|
||
|
typedef struct _RecordQueue RecordQueue;
|
||
|
|
||
|
struct _RecordQueueList {
|
||
|
DesktopRecord *drecord;
|
||
|
PilotRecord *precord;
|
||
|
|
||
|
RecordQueueList *next;
|
||
|
};
|
||
|
|
||
|
struct _RecordQueue {
|
||
|
int count;
|
||
|
|
||
|
RecordQueueList *rql;
|
||
|
};
|
||
|
|
||
|
|
||
|
#define PilotCheck(func) if (rec_mod == PILOT || rec_mod == BOTH) if ((result = func) < 0) return result;
|
||
|
#define DesktopCheck(func) if (rec_mod == DESKTOP || rec_mod == BOTH) if ((result = func) < 0) return result;
|
||
|
#define ErrorCheck(func) if ((result = func) < 0) return result;
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_NewPilotRecord
|
||
|
*
|
||
|
* Summary: Create a new, empty device record with the given buffer
|
||
|
* size
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: The new device record
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
PilotRecord *sync_NewPilotRecord(int buf_size)
|
||
|
{
|
||
|
PilotRecord *precord;
|
||
|
|
||
|
precord = (PilotRecord *) malloc(sizeof(PilotRecord));
|
||
|
memset(precord, 0, sizeof(PilotRecord));
|
||
|
|
||
|
precord->buffer = malloc(buf_size);
|
||
|
|
||
|
return precord;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_CopyPilotRecord
|
||
|
*
|
||
|
* Summary: Copies the given device record
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: The device record passed by sync_NewPilotRecord
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
PilotRecord *sync_CopyPilotRecord(const PilotRecord * precord)
|
||
|
{
|
||
|
PilotRecord *new_record;
|
||
|
|
||
|
new_record = sync_NewPilotRecord(sizeof(precord->buffer));
|
||
|
|
||
|
new_record->recID = precord->recID;
|
||
|
new_record->catID = precord->catID;
|
||
|
new_record->flags = precord->flags;
|
||
|
memcpy(new_record->buffer, precord->buffer, precord->len);
|
||
|
new_record->len = precord->len;
|
||
|
|
||
|
return new_record;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_FreePilotRecord
|
||
|
*
|
||
|
* Summary: Free the memory of the given device record
|
||
|
*
|
||
|
* Parameters: The device record to free
|
||
|
*
|
||
|
* Returns: Nothing
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
void sync_FreePilotRecord(PilotRecord * precord)
|
||
|
{
|
||
|
if (precord->buffer)
|
||
|
free(precord->buffer);
|
||
|
|
||
|
free(precord);
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_NewDesktopRecord
|
||
|
*
|
||
|
* Summary: Create a new, empty, desktop record
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: The new, empty desktop record
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
DesktopRecord *sync_NewDesktopRecord(void)
|
||
|
{
|
||
|
DesktopRecord *drecord;
|
||
|
|
||
|
drecord = (DesktopRecord *) malloc(sizeof(DesktopRecord));
|
||
|
memset(drecord, 0, sizeof(DesktopRecord));
|
||
|
|
||
|
return drecord;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_CopyDesktopRecord
|
||
|
*
|
||
|
* Summary: Copies the given desktop record
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: The new desktop record (DesktopRecord)
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
DesktopRecord *sync_CopyDesktopRecord(const DesktopRecord * drecord)
|
||
|
{
|
||
|
DesktopRecord *new_record;
|
||
|
|
||
|
new_record = sync_NewDesktopRecord();
|
||
|
*new_record = *drecord;
|
||
|
|
||
|
return new_record;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_FreeDesktopRecord
|
||
|
*
|
||
|
* Summary: Free the memory of the given desktop record
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: Nothing
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
void sync_FreeDesktopRecord(DesktopRecord * drecord)
|
||
|
{
|
||
|
free(drecord);
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: add_record_queue
|
||
|
*
|
||
|
* Summary: Add records to process to the queue, until no more
|
||
|
* records exist
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: Nothing
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static void
|
||
|
add_record_queue(RecordQueue * rq, PilotRecord * precord,
|
||
|
DesktopRecord * drecord)
|
||
|
{
|
||
|
RecordQueueList *item;
|
||
|
|
||
|
item = malloc(sizeof(RecordQueueList));
|
||
|
|
||
|
if (drecord != NULL) {
|
||
|
item->drecord = drecord;
|
||
|
item->precord = NULL;
|
||
|
} else {
|
||
|
item->drecord = NULL;
|
||
|
item->precord = sync_CopyPilotRecord(precord);
|
||
|
}
|
||
|
|
||
|
if (rq) {
|
||
|
item->next = rq->rql;
|
||
|
rq->rql = item;
|
||
|
} else {
|
||
|
item->next = NULL;
|
||
|
}
|
||
|
|
||
|
rq->count++;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: free_record_queue_list
|
||
|
*
|
||
|
* Summary: Free the list
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: Nothing
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int free_record_queue_list(SyncHandler * sh, RecordQueueList * rql)
|
||
|
{
|
||
|
int result = 0;
|
||
|
RecordQueueList *item;
|
||
|
|
||
|
while (rql != NULL) {
|
||
|
item = rql;
|
||
|
rql = rql->next;
|
||
|
|
||
|
if (item->drecord)
|
||
|
ErrorCheck(sh->FreeMatch(sh, item->drecord));
|
||
|
if (item->precord)
|
||
|
sync_FreePilotRecord(item->precord);
|
||
|
|
||
|
free(item);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: delete_both
|
||
|
*
|
||
|
* Summary: Delete records from both Palm and desktop, same time
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: negative number if error, otherwise 0 to indicate
|
||
|
* success
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
delete_both(SyncHandler * sh, int dbhandle, DesktopRecord * drecord,
|
||
|
PilotRecord * precord, RecordModifier rec_mod)
|
||
|
{
|
||
|
int result = 0;
|
||
|
|
||
|
if (drecord != NULL)
|
||
|
DesktopCheck(sh->DeleteRecord(sh, drecord));
|
||
|
|
||
|
if (precord != NULL)
|
||
|
PilotCheck(dlp_DeleteRecord
|
||
|
(sh->sd, dbhandle, 0, precord->recID));
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: store_record_on_pilot
|
||
|
*
|
||
|
* Summary: Store the new/modified record on the Palm
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 if success, otherwise negative number
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
store_record_on_pilot(SyncHandler * sh, int dbhandle,
|
||
|
DesktopRecord * drecord, RecordModifier rec_mod)
|
||
|
{
|
||
|
int result = 0;
|
||
|
PilotRecord precord;
|
||
|
recordid_t id_;
|
||
|
|
||
|
memset(&precord, 0, sizeof(PilotRecord));
|
||
|
|
||
|
result = sh->Prepare(sh, drecord, &precord);
|
||
|
if (result != 0)
|
||
|
return result;
|
||
|
|
||
|
PilotCheck(dlp_WriteRecord(sh->sd, dbhandle, precord.flags & dlpRecAttrSecret,
|
||
|
precord.recID, precord.catID,
|
||
|
precord.buffer, precord.len, &id_));
|
||
|
|
||
|
DesktopCheck(sh->SetPilotID(sh, drecord, id_));
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: open_db
|
||
|
*
|
||
|
* Summary: Open a given database by handle for operation
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: Nothing
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int open_db(SyncHandler * sh, int *dbhandle)
|
||
|
{
|
||
|
if (sh->secret)
|
||
|
return dlp_OpenDB(sh->sd, 0, dlpOpenReadWrite
|
||
|
&& dlpOpenSecret, sh->name, dbhandle);
|
||
|
else
|
||
|
return dlp_OpenDB(sh->sd, 0, dlpOpenReadWrite, sh->name,
|
||
|
dbhandle);
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: close_db
|
||
|
*
|
||
|
* Summary: Close a given database by handle
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: Nothing
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int close_db(SyncHandler * sh, int dbhandle)
|
||
|
{
|
||
|
dlp_CleanUpDatabase(sh->sd, dbhandle);
|
||
|
|
||
|
dlp_ResetSyncFlags(sh->sd, dbhandle);
|
||
|
dlp_CloseDB(sh->sd, dbhandle);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_record
|
||
|
*
|
||
|
* Summary: Synchronize a record to the Palm
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 if success, otherwise return a negative number
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
sync_record(SyncHandler * sh, int dbhandle,
|
||
|
DesktopRecord * drecord, PilotRecord * precord,
|
||
|
RecordQueue * rq, RecordModifier rec_mod)
|
||
|
{
|
||
|
int parch = 0,
|
||
|
pdel = 0,
|
||
|
pchange = 0,
|
||
|
darch = 0,
|
||
|
ddel = 0,
|
||
|
dchange = 0,
|
||
|
result = 0;
|
||
|
|
||
|
/* The state is calculated like this because the deleted and dirty
|
||
|
pilot flags are not mutually exclusive */
|
||
|
if (precord) {
|
||
|
parch = precord->flags & dlpRecAttrArchived;
|
||
|
pdel = precord->flags & dlpRecAttrDeleted;
|
||
|
pchange = (precord->flags & dlpRecAttrDirty) && (!pdel);
|
||
|
}
|
||
|
|
||
|
if (drecord) {
|
||
|
darch = drecord->flags & dlpRecAttrArchived;
|
||
|
ddel = drecord->flags & dlpRecAttrDeleted;
|
||
|
dchange = (drecord->flags & dlpRecAttrDirty) && (!ddel);
|
||
|
}
|
||
|
|
||
|
/* Bail if the pilot record was created and deleted between syncs */
|
||
|
if (drecord == NULL && !parch && pdel)
|
||
|
return 0;
|
||
|
|
||
|
/* Sync logic */
|
||
|
if (precord != NULL && !parch && !pdel && drecord == NULL) {
|
||
|
DesktopCheck(sh->AddRecord(sh, precord));
|
||
|
|
||
|
} else if (precord == NULL && drecord != NULL) {
|
||
|
add_record_queue(rq, NULL, drecord);
|
||
|
|
||
|
} else if (parch && ddel) {
|
||
|
DesktopCheck(sh->ReplaceRecord(sh, drecord, precord));
|
||
|
DesktopCheck(sh->ArchiveRecord(sh, drecord, 1));
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (parch && !darch && !dchange && drecord != NULL) {
|
||
|
DesktopCheck(sh->ArchiveRecord(sh, drecord, 1));
|
||
|
|
||
|
} else if (parch && drecord == NULL) {
|
||
|
DesktopCheck(sh->AddRecord(sh, precord));
|
||
|
ErrorCheck(sh->Match(sh, precord, &drecord));
|
||
|
if (drecord == NULL)
|
||
|
return -1;
|
||
|
DesktopCheck(sh->ArchiveRecord(sh, drecord, 1));
|
||
|
ErrorCheck(sh->FreeMatch(sh, drecord));
|
||
|
|
||
|
} else if (parch && pchange && !darch && dchange) {
|
||
|
int comp;
|
||
|
|
||
|
comp = sh->Compare(sh, precord, drecord);
|
||
|
if (comp == 0) {
|
||
|
DesktopCheck(sh->ArchiveRecord(sh, drecord, 1));
|
||
|
PilotCheck(dlp_DeleteRecord
|
||
|
(sh->sd, dbhandle, 0, precord->recID));
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
} else {
|
||
|
PilotCheck(dlp_WriteRecord(sh->sd, dbhandle, 0, 0,
|
||
|
precord->catID,
|
||
|
precord->buffer,
|
||
|
precord->len,
|
||
|
&precord->recID));
|
||
|
DesktopCheck(sh->AddRecord(sh, precord));
|
||
|
add_record_queue(rq, NULL, drecord);
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
}
|
||
|
|
||
|
} else if (parch && !pchange && !darch && dchange) {
|
||
|
PilotCheck(dlp_DeleteRecord
|
||
|
(sh->sd, dbhandle, 0, precord->recID));
|
||
|
add_record_queue(rq, NULL, drecord);
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (pchange && darch && dchange) {
|
||
|
int comp;
|
||
|
|
||
|
comp = sh->Compare(sh, precord, drecord);
|
||
|
if (comp == 0) {
|
||
|
PilotCheck(dlp_DeleteRecord
|
||
|
(sh->sd, dbhandle, 0, precord->recID));
|
||
|
} else {
|
||
|
DesktopCheck(sh->ArchiveRecord(sh, drecord, 0));
|
||
|
DesktopCheck(sh->
|
||
|
ReplaceRecord(sh, drecord, precord));
|
||
|
}
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (pchange && darch && !dchange) {
|
||
|
DesktopCheck(sh->ArchiveRecord(sh, drecord, 0));
|
||
|
DesktopCheck(sh->ReplaceRecord(sh, drecord, precord));
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (pchange && dchange) {
|
||
|
int comp;
|
||
|
|
||
|
comp = sh->Compare(sh, precord, drecord);
|
||
|
if (comp != 0) {
|
||
|
DesktopCheck(sh->AddRecord(sh, precord));
|
||
|
drecord->recID = 0;
|
||
|
add_record_queue(rq, NULL, drecord);
|
||
|
}
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (pchange && ddel) {
|
||
|
DesktopCheck(sh->ReplaceRecord(sh, drecord, precord));
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (pchange && !dchange) {
|
||
|
DesktopCheck(sh->ReplaceRecord(sh, drecord, precord));
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (pdel && dchange) {
|
||
|
add_record_queue(rq, NULL, drecord);
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (pdel && !dchange) {
|
||
|
DesktopCheck(delete_both
|
||
|
(sh, dbhandle, drecord, precord, rec_mod));
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (!pchange && darch) {
|
||
|
PilotCheck(dlp_DeleteRecord
|
||
|
(sh->sd, dbhandle, 0, precord->recID));
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (!pchange && dchange) {
|
||
|
PilotCheck(dlp_DeleteRecord
|
||
|
(sh->sd, dbhandle, 0, precord->recID));
|
||
|
add_record_queue(rq, NULL, drecord);
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
} else if (!pchange && ddel) {
|
||
|
DesktopCheck(delete_both
|
||
|
(sh, dbhandle, drecord, precord, rec_mod));
|
||
|
DesktopCheck(sh->SetStatusCleared(sh, drecord));
|
||
|
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_CopyToPilot
|
||
|
*
|
||
|
* Summary: Copy all desktop records to the Palm
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 on success, non-zero otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
int sync_CopyToPilot(SyncHandler * sh)
|
||
|
{
|
||
|
int dbhandle,
|
||
|
slow = 0,
|
||
|
result = 0;
|
||
|
DesktopRecord *drecord = NULL;
|
||
|
|
||
|
result = open_db(sh, &dbhandle);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
result = sh->Pre(sh, dbhandle, &slow);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
result = dlp_DeleteRecord(sh->sd, dbhandle, 1, 0);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
|
||
|
while (sh->ForEach(sh, &drecord) == 0 && drecord) {
|
||
|
result =
|
||
|
store_record_on_pilot(sh, dbhandle, drecord, BOTH);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
result = sh->Post(sh, dbhandle);
|
||
|
|
||
|
cleanup:
|
||
|
close_db(sh, dbhandle);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_CopyFromPilot
|
||
|
*
|
||
|
* Summary: Copy all device records from the Palm to the desktop
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 on success, non-zero otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
int sync_CopyFromPilot(SyncHandler * sh)
|
||
|
{
|
||
|
int dbhandle,
|
||
|
i,
|
||
|
slow = 0,
|
||
|
result = 0;
|
||
|
pi_buffer_t *recbuf;
|
||
|
|
||
|
DesktopRecord *drecord = NULL;
|
||
|
PilotRecord *precord = sync_NewPilotRecord(DLP_BUF_SIZE);
|
||
|
|
||
|
result = open_db(sh, &dbhandle);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
result = sh->Pre(sh, dbhandle, &slow);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
while (sh->ForEach(sh, &drecord) == 0 && drecord) {
|
||
|
result = sh->DeleteRecord(sh, drecord);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
i = 0;
|
||
|
recbuf = pi_buffer_new(DLP_BUF_SIZE);
|
||
|
while (dlp_ReadRecordByIndex(sh->sd, dbhandle, i, recbuf, &precord->recID,
|
||
|
&precord->flags, &precord->catID) > 0) {
|
||
|
precord->len = recbuf->used;
|
||
|
if (precord->len > DLP_BUF_SIZE)
|
||
|
precord->len = DLP_BUF_SIZE;
|
||
|
memcpy(precord->buffer, recbuf->data, precord->len);
|
||
|
result = sh->AddRecord(sh, precord);
|
||
|
if (result < 0) {
|
||
|
pi_buffer_free(recbuf);
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
i++;
|
||
|
}
|
||
|
pi_buffer_free (recbuf);
|
||
|
|
||
|
result = sh->Post(sh, dbhandle);
|
||
|
|
||
|
cleanup:
|
||
|
close_db(sh, dbhandle);
|
||
|
sync_FreePilotRecord (precord);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_MergeFromPilot_process
|
||
|
*
|
||
|
* Summary: Try to be intelligent about merging data in a record
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: Nothing
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
sync_MergeFromPilot_process(SyncHandler * sh, int dbhandle,
|
||
|
RecordQueue * rq, RecordModifier rec_mod)
|
||
|
{
|
||
|
int result = 0;
|
||
|
RecordQueueList *item;
|
||
|
|
||
|
for (item = rq->rql; item != NULL; item = item->next) {
|
||
|
if (item->drecord != NULL) {
|
||
|
store_record_on_pilot(sh, dbhandle, item->drecord,
|
||
|
rec_mod);
|
||
|
} else {
|
||
|
PilotCheck(dlp_WriteRecord(sh->sd, dbhandle, 0, 0,
|
||
|
item->precord->catID,
|
||
|
item->precord->buffer,
|
||
|
item->precord->len,
|
||
|
&item->precord->recID));
|
||
|
}
|
||
|
}
|
||
|
free_record_queue_list(sh, rq->rql);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_MergeFromPilot_fast
|
||
|
*
|
||
|
* Summary: er, fast merge from Palm to desktop
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 if success, nonzero otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
sync_MergeFromPilot_fast(SyncHandler * sh, int dbhandle,
|
||
|
RecordModifier rec_mod)
|
||
|
{
|
||
|
int result = 0;
|
||
|
PilotRecord *precord = sync_NewPilotRecord(DLP_BUF_SIZE);
|
||
|
DesktopRecord *drecord = NULL;
|
||
|
RecordQueue rq = { 0, NULL };
|
||
|
pi_buffer_t *recbuf = pi_buffer_new(DLP_BUF_SIZE);
|
||
|
|
||
|
while (dlp_ReadNextModifiedRec(sh->sd, dbhandle, recbuf,
|
||
|
&precord->recID, NULL,
|
||
|
&precord->flags,
|
||
|
&precord->catID) >= 0) {
|
||
|
int count = rq.count;
|
||
|
precord->len = recbuf->used;
|
||
|
if (precord->len > DLP_BUF_SIZE)
|
||
|
precord->len = DLP_BUF_SIZE;
|
||
|
memcpy(precord->buffer, recbuf->data, precord->len);
|
||
|
ErrorCheck(sh->Match(sh, precord, &drecord));
|
||
|
ErrorCheck(sync_record
|
||
|
(sh, dbhandle, drecord, precord, &rq, rec_mod));
|
||
|
|
||
|
if (drecord && rq.count == count)
|
||
|
ErrorCheck(sh->FreeMatch(sh, drecord));
|
||
|
}
|
||
|
pi_buffer_free(recbuf);
|
||
|
sync_FreePilotRecord(precord);
|
||
|
|
||
|
result = sync_MergeFromPilot_process(sh, dbhandle, &rq, rec_mod);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_MergeFromPilot_slow
|
||
|
*
|
||
|
* Summary: uh, slow merge from Palm to desktop
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 if success, nonzero otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
sync_MergeFromPilot_slow(SyncHandler * sh, int dbhandle,
|
||
|
RecordModifier rec_mod)
|
||
|
{
|
||
|
int i,
|
||
|
parch,
|
||
|
psecret,
|
||
|
result = 0;
|
||
|
pi_buffer_t *recbuf;
|
||
|
|
||
|
PilotRecord *precord = sync_NewPilotRecord(DLP_BUF_SIZE);
|
||
|
DesktopRecord *drecord = NULL;
|
||
|
RecordQueue rq = { 0, NULL };
|
||
|
|
||
|
i = 0;
|
||
|
recbuf = pi_buffer_new(DLP_BUF_SIZE);
|
||
|
while (dlp_ReadRecordByIndex
|
||
|
(sh->sd, dbhandle, i, recbuf, &precord->recID,
|
||
|
&precord->flags, &precord->catID) > 0) {
|
||
|
int count = rq.count;
|
||
|
|
||
|
precord->len = recbuf->used;
|
||
|
if (precord->len > DLP_BUF_SIZE)
|
||
|
precord->len = DLP_BUF_SIZE;
|
||
|
memcpy(precord->buffer, recbuf->data, precord->len);
|
||
|
|
||
|
ErrorCheck(sh->Match(sh, precord, &drecord));
|
||
|
|
||
|
/* Since this is a slow sync, we must calculate the flags */
|
||
|
parch = precord->flags & dlpRecAttrArchived;
|
||
|
psecret = precord->flags & dlpRecAttrSecret;
|
||
|
|
||
|
precord->flags = 0;
|
||
|
if (drecord == NULL) {
|
||
|
precord->flags = precord->flags | dlpRecAttrDirty;
|
||
|
} else {
|
||
|
int comp;
|
||
|
|
||
|
comp = sh->Compare(sh, precord, drecord);
|
||
|
if (comp != 0) {
|
||
|
precord->flags =
|
||
|
precord->flags | dlpRecAttrDirty;
|
||
|
}
|
||
|
}
|
||
|
if (parch)
|
||
|
precord->flags =
|
||
|
precord->flags | dlpRecAttrArchived;
|
||
|
if (psecret)
|
||
|
precord->flags = precord->flags | dlpRecAttrSecret;
|
||
|
|
||
|
ErrorCheck(sync_record
|
||
|
(sh, dbhandle, drecord, precord, &rq, rec_mod));
|
||
|
|
||
|
if (drecord && rq.count == count)
|
||
|
ErrorCheck(sh->FreeMatch(sh, drecord));
|
||
|
|
||
|
i++;
|
||
|
}
|
||
|
pi_buffer_free(recbuf);
|
||
|
|
||
|
sync_FreePilotRecord(precord);
|
||
|
|
||
|
result = sync_MergeFromPilot_process(sh, dbhandle, &rq, rec_mod);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_MergeFromPilot
|
||
|
*
|
||
|
* Summary: Synchronize the device records to the desktop, but do
|
||
|
* not alter the device records
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 on success, non-zero otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
int sync_MergeFromPilot(SyncHandler * sh)
|
||
|
{
|
||
|
int dbhandle,
|
||
|
slow = 0,
|
||
|
result = 0;
|
||
|
|
||
|
result = open_db(sh, &dbhandle);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
result = sh->Pre(sh, dbhandle, &slow);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
if (!slow) {
|
||
|
result = sync_MergeFromPilot_fast(sh, dbhandle, DESKTOP);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
} else {
|
||
|
result = sync_MergeFromPilot_slow(sh, dbhandle, DESKTOP);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
result = sh->Post(sh, dbhandle);
|
||
|
|
||
|
cleanup:
|
||
|
close_db(sh, dbhandle);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_MergeToPilot_fast
|
||
|
*
|
||
|
* Summary: Fast merge from desktop to Palm
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 on success, non-zero otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
sync_MergeToPilot_fast(SyncHandler * sh, int dbhandle,
|
||
|
RecordModifier rec_mod)
|
||
|
{
|
||
|
int result = 0;
|
||
|
PilotRecord *precord = NULL;
|
||
|
DesktopRecord *drecord = NULL;
|
||
|
RecordQueue rq = { 0, NULL };
|
||
|
pi_buffer_t *recbuf = pi_buffer_new(DLP_BUF_SIZE);
|
||
|
|
||
|
while (sh->ForEachModified(sh, &drecord) == 0 && drecord) {
|
||
|
if (drecord->recID != 0) {
|
||
|
precord = sync_NewPilotRecord(DLP_BUF_SIZE);
|
||
|
precord->recID = drecord->recID;
|
||
|
PilotCheck(dlp_ReadRecordById(sh->sd, dbhandle,
|
||
|
precord->recID,
|
||
|
recbuf,
|
||
|
NULL,
|
||
|
&precord->flags,
|
||
|
&precord->catID));
|
||
|
precord->len = recbuf->used;
|
||
|
if (precord->len > DLP_BUF_SIZE)
|
||
|
precord->len = DLP_BUF_SIZE;
|
||
|
memcpy(precord->buffer, recbuf->data, precord->len);
|
||
|
}
|
||
|
|
||
|
ErrorCheck(sync_record
|
||
|
(sh, dbhandle, drecord, precord, &rq, rec_mod));
|
||
|
|
||
|
if (precord)
|
||
|
sync_FreePilotRecord (precord);
|
||
|
precord = NULL;
|
||
|
}
|
||
|
pi_buffer_free(recbuf);
|
||
|
|
||
|
result = sync_MergeFromPilot_process(sh, dbhandle, &rq, rec_mod);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_MergeToPilot_slow
|
||
|
*
|
||
|
* Summary: Slow merge from desktop to Palm
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 on success, non-zero otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
static int
|
||
|
sync_MergeToPilot_slow(SyncHandler * sh, int dbhandle,
|
||
|
RecordModifier rec_mod)
|
||
|
{
|
||
|
int darch,
|
||
|
dsecret,
|
||
|
result = 0;
|
||
|
PilotRecord *precord = NULL;
|
||
|
DesktopRecord *drecord = NULL;
|
||
|
RecordQueue rq = { 0, NULL };
|
||
|
pi_buffer_t *recbuf = pi_buffer_new(DLP_BUF_SIZE);
|
||
|
|
||
|
while (sh->ForEach(sh, &drecord) == 0 && drecord) {
|
||
|
if (drecord->recID != 0) {
|
||
|
precord = sync_NewPilotRecord(DLP_BUF_SIZE);
|
||
|
precord->recID = drecord->recID;
|
||
|
PilotCheck(dlp_ReadRecordById(sh->sd, dbhandle,
|
||
|
precord->recID,
|
||
|
recbuf,
|
||
|
NULL,
|
||
|
&precord->flags,
|
||
|
&precord->catID));
|
||
|
precord->len = recbuf->used;
|
||
|
if (precord->len > DLP_BUF_SIZE)
|
||
|
precord->len = DLP_BUF_SIZE;
|
||
|
memcpy(precord->buffer, recbuf->data, precord->len);
|
||
|
}
|
||
|
|
||
|
/* Since this is a slow sync, we must calculate the flags */
|
||
|
darch = drecord->flags & dlpRecAttrArchived;
|
||
|
dsecret = drecord->flags & dlpRecAttrSecret;
|
||
|
|
||
|
drecord->flags = 0;
|
||
|
if (precord == NULL) {
|
||
|
drecord->flags = drecord->flags | dlpRecAttrDirty;
|
||
|
} else {
|
||
|
int comp;
|
||
|
|
||
|
comp = sh->Compare(sh, precord, drecord);
|
||
|
if (comp != 0) {
|
||
|
drecord->flags =
|
||
|
drecord->flags | dlpRecAttrDirty;
|
||
|
}
|
||
|
}
|
||
|
if (darch)
|
||
|
drecord->flags =
|
||
|
drecord->flags | dlpRecAttrArchived;
|
||
|
if (dsecret)
|
||
|
drecord->flags = drecord->flags | dlpRecAttrSecret;
|
||
|
|
||
|
ErrorCheck(sync_record
|
||
|
(sh, dbhandle, drecord, precord, &rq, rec_mod));
|
||
|
|
||
|
if (precord)
|
||
|
sync_FreePilotRecord (precord);
|
||
|
precord = NULL;
|
||
|
}
|
||
|
pi_buffer_free(recbuf);
|
||
|
|
||
|
result = sync_MergeFromPilot_process(sh, dbhandle, &rq, rec_mod);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_MergeToPilot
|
||
|
*
|
||
|
* Summary: Synchronize the desktop records to the pilot, but do
|
||
|
* not alter the desktop records
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 on success, non-zero otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
int sync_MergeToPilot(SyncHandler * sh)
|
||
|
{
|
||
|
int dbhandle,
|
||
|
slow = 0,
|
||
|
result = 0;
|
||
|
|
||
|
result = open_db(sh, &dbhandle);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
result = sh->Pre(sh, dbhandle, &slow);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
if (!slow) {
|
||
|
sync_MergeToPilot_fast(sh, dbhandle, PILOT);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
} else {
|
||
|
sync_MergeToPilot_slow(sh, dbhandle, PILOT);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
result = sh->Post(sh, dbhandle);
|
||
|
|
||
|
cleanup:
|
||
|
close_db(sh, dbhandle);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Function: sync_Synchronize
|
||
|
*
|
||
|
* Summary: Synchronizes the pilot database and the desktop database
|
||
|
*
|
||
|
* Parameters: None
|
||
|
*
|
||
|
* Returns: 0 on success, non-zero otherwise
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
int sync_Synchronize(SyncHandler * sh)
|
||
|
{
|
||
|
int dbhandle,
|
||
|
slow = 0,
|
||
|
result = 0;
|
||
|
|
||
|
result = open_db(sh, &dbhandle);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
result = sh->Pre(sh, dbhandle, &slow);
|
||
|
if (result != 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
if (!slow) {
|
||
|
result = sync_MergeFromPilot_fast(sh, dbhandle, BOTH);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
result = sync_MergeToPilot_fast(sh, dbhandle, BOTH);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
} else {
|
||
|
result = sync_MergeFromPilot_slow(sh, dbhandle, BOTH);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
|
||
|
result = sync_MergeToPilot_slow(sh, dbhandle, BOTH);
|
||
|
if (result < 0)
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
result = sh->Post(sh, dbhandle);
|
||
|
|
||
|
cleanup:
|
||
|
close_db(sh, dbhandle);
|
||
|
|
||
|
return result;
|
||
|
}
|