ic35link/src/ic35sync.c

981 lines
29 KiB
C

/************************************************************************
* Copyright (C) 2000,2001 Thomas Schulz *
* */
static char rcsid[] =
"$Id: ic35sync.c,v 1.19 2001/03/02 02:10:42 tsch Rel $"; /*
* *
* IC35 synchronize PIM data *
* *
*************************************************************************
* *
* ??? is "fixme" mark: sections of code needing fixes *
* *
* conditional compile on NO_LOGSIM: if #defined, logging of the *
* IC35 communications as well as simulated communication are NOT *
* supported, default WITH logging and com-simulation support. *
* *
* for usage run ic35sync -h or see function usage() below. *
* *
************************************************************************/
#include <stdio.h> /* printf(), .. */
#include <string.h> /* strcmp(), .. */
#include <getopt.h> /* getopt(), optarg, .. */
#include <time.h> /* struct tm, time() .. */
#include "util.h" /* FALSE, .. */
#include "comio.h" /* com_siminit() */
#include "syntrans.h" /* IC35sync transactions */
#include "ic35frec.h" /* FILEADDR, .. */
#include "dataio.h" /* IC35sync import/export */
NOTUSED(rcsid)
extern char * pkgvers; /* these are all */
extern char * pkgdate; /* in versinfo.c, which is */
extern char * bldinfo; /* auto-generated by Makefile */
static const int fileids[4] = {
FILEADDR,
FILEMEMO,
FILESCHED,
FILETODO
};
/* report IC35 status
* ------------------
* show firmware version, sysinfo (date+time), total and modified
* number of records per IC35 file.
*/
static int
ic35status( char * devname, char * passwd )
{
int i, fileid;
int fd;
char * fname;
int nrec, nmod, nspc;
int rval;
char ic35dtime[16+1];
if ( (rval = connect( devname, passwd, ic35dtime )) != OK )
return rval;
for ( i = 0; i < sizeof(fileids)/sizeof(fileids[0]); ++i ) {
fileid = fileids[i];
rval = ERR;
if ( (fname = ic35fname( fileid )) == NULL ) {
error( "status failed: bad fileid %02X", fileid );
break;
}
LPRINTF(( L_INFO, "status fid=%02X \"%s\" ..", fileid, fname ));
if ( (fd = open_file( ic35fname( fileid ) )) >= 0 ) {
if ( (nrec = get_flen( fd )) >= 0 ) {
if ( (nmod = get_mod_flen( fd )) >= 0 ) {
if ( (nspc = 10 - strlen( fname )) < 0 ) nspc = 0;
message( "status \"%s\"%*s total %2d modified %2d records",
fname, nspc, "", nrec, nmod );
rval = OK;
} else
error( "status %s failed: get_mod_flen failed", fname );
} else
error( "status %s failed: get_flen failed", fname );
close_file( fd );
} else
error( "status %s failed: open_file failed", fname );
LPRINTF(( L_INFO, "status fid=%02X \"%s\" %s", fileid, fname,
rval == OK ? "OK" : "ERR" ));
if ( rval != OK )
break;
}
disconnect();
return rval;
}
/* run IC35 export session
* -----------------------
* read all IC35 records and export (i.e. add/update) to PIMfile:
* - set modified+created time in PIMrecord if added IC35 record
* - set modified time in PIMrecord if updated from IC35 record
* - do not change modified time in PIMrecord if same as IC35 record
* - set PIMrecord status to CLEAN if added/updated/same as IC35
* - set IC35 record-ID to added/updated PIMfile records
* changeflags of records in IC35 will not be reset,
* records in IC35 will not be modified/deleted, and
* sysinfo (date+time) will not be written to IC35.
* IC35 overrides PIMfile, PIMfile records not in IC35 remain untouched.
*/
static int
exportfile( int fileid )
{
char * fname;
int fd, nrec, irec;
IC35REC * rec;
int rval;
if ( (fname = ic35fname( fileid )) == NULL ) {
error( "export failed: bad fileid %02X", fileid );
return ERR;
}
LPRINTF(( L_INFO, "exportfile(fid=%02X) \"%s\" ..", fileid, fname ));
if ( (rec = new_ic35rec()) == NULL ) {
error( "export %s failed: no memory", fname );
return ERR;
}
if ( (fd = open_file( ic35fname( fileid ) )) < 0 ) {
error( "export %s failed: open_file failed", fname );
del_ic35rec( rec );
return ERR;
}
if ( (nrec = get_flen( fd )) < 0 ) {
error( "export %s failed: get_flen failed", fname );
close_file( fd );
del_ic35rec( rec );
return ERR;
}
message( "export \"%s\", %d records", fname, nrec );
rval = OK;
for ( irec = 0; irec < nrec; ++irec ) {
if ( read_frec( fd, irec, rec ) < 0 ) {
rval = ERR;
break;
}
pim_putic35rec( rec );
}
close_file( fd );
del_ic35rec( rec );
LPRINTF(( L_INFO, "exportfile(fid=%02X) \"%s\" %s",
fileid, fname, rval == OK ? "OK" : "ERR" ));
return rval;
}
static int
ic35export( char * devname, char * passwd )
{
int i, rval;
if ( (rval = connect( devname, passwd, NULL )) != 0 )
return rval;
for ( i = 0; i < sizeof(fileids)/sizeof(fileids[0]); ++i )
if ( (rval = exportfile( fileids[i] )) != OK )
break;
disconnect();
return rval;
}
/* maintain IC35 record table for import,sync
* ------------------------------------------
*/
enum ic35op { /* IC35 record operation */
IC35NOACT, /* 0 no action */
IC35DELETE, /* 1 delete record */
IC35WRITE, /* 2 write new record */
IC35UPDATE, /* 3 re-write existing record */
IC35COMMIT, /* 4 commit clears changeflag */
};
struct recop { /* IC35 record,op entry */
IC35REC * rec; /* ptr to IC35 record */
enum ic35op op; /* record operation to do */
void * pim; /* ptr to PIM record */
};
static struct recop * _ic35rectab;
static size_t _ic35rectablen;
#define ADD_CHUNKS 64
/* put IC35 record and action into table
* -------------------------------------
* if record already in table, just update action
* if free entry available, put record,action there
* if table full or not allocated yet, make it bigger
* in chunks of
*/
static void
_put_ic35recs( IC35REC * ic35rec, enum ic35op action, void * pimrec )
{
int i;
struct recop * ntab;
size_t nlen;
for ( i = 0; i < _ic35rectablen; ++i ) {
if ( _ic35rectab[i].rec == ic35rec ) {
_ic35rectab[i].op = action;
_ic35rectab[i].pim = pimrec;
return;
}
if ( _ic35rectab[i].rec == NULL )
break;
}
if ( i >= _ic35rectablen ) {
nlen = _ic35rectablen + ADD_CHUNKS;
if ( (ntab = realloc( _ic35rectab, nlen * sizeof(ntab[0]) )) == NULL )
return;
memset( ntab+_ic35rectablen, 0, ADD_CHUNKS * sizeof(ntab[0]) );
_ic35rectab = ntab;
_ic35rectablen = nlen;
}
_ic35rectab[i].rec = ic35rec;
_ic35rectab[i].op = action;
_ic35rectab[i].pim = pimrec;
}
/* get IC35 record and action from table
* -------------------------------------
* if non-zero 'recid' lookup IC35 record with that record-ID,
* otherwise just retrieve first non-NULL record in table.
* pass action associated with record to non-NULL 'paction'.
* the record will be removed from table !
*/
static IC35REC *
_get_ic35recs( ulong recid, enum ic35op * paction, void ** ppimrec )
{
int i;
IC35REC * rec;
for ( i = 0; i < _ic35rectablen; ++i ) {
if ( (rec = _ic35rectab[i].rec) == NULL )
continue;
if ( recid == 0 || ic35recid( rec ) == recid ) {
if ( paction ) *paction = _ic35rectab[i].op;
if ( ppimrec ) *ppimrec = _ic35rectab[i].pim;
_ic35rectab[i].op = IC35NOACT;
_ic35rectab[i].rec = NULL;
return rec;
}
}
return NULL;
}
/* delete IC35 record table
* ------------------------
* release all non-NULL records in table, then release table
* return number of records yet in table, used by "import" to
* detect records in IC35 but not in PIMfile.
*/
static int
_del_ic35recs( void )
{
int i;
int only_ic35;
for ( i = only_ic35 = 0; i < _ic35rectablen; ++i )
if ( _ic35rectab[i].rec != NULL ) {
++only_ic35; /* IC35 record not in PIMfile */
del_ic35rec( _ic35rectab[i].rec );
}
free( _ic35rectab );
_ic35rectab = NULL;
_ic35rectablen = 0;
return only_ic35; /* num.of records not in PIMfile */
}
/* run IC35 import session
* -----------------------
* read all records from IC35 and compare with PIMfile
* - update PIMrecord to IC35 if same record-ID on IC35
* - write PIMrecord to IC35 if record not on IC35
* and write back new IC35 record-ID to PIMrecord
* - reset IC35 record changeflag if same as PIMrecord
* - set PIMrecord status to CLEAN
* - owner address data must be written with update_frec() and recID 1
* otherwise on IC35 in category "Address", but not as owner data
* do not delete records neither in IC35 nor in PIMfile
* write sysinfo (date+time) if all IC35 records match PIMfile
* PIMfile overrides IC35, IC35 records not in PIMfile remain untouched,
* sysinfo (date+time) is not written if any IC35 record not in PIMfile.
*/
static int
importfile( int fileid, char * ic35dtime )
{
char * fname;
int fd, nrec, irec;
IC35REC * ic35rec;
void * pimrec;
ulong recid;
int n_write, n_update, n_commit;
int ic35_not_in_PIM;
enum ic35op action;
char * actext;
int rc, rval;
if ( (fname = ic35fname( fileid )) == NULL ) {
error( "import failed: bad fileid %02X", fileid );
return ERR;
}
LPRINTF(( L_INFO, "importfile(fid=%02X) \"%s\" ..", fileid, fname ));
if ( (fd = open_file( ic35fname( fileid ) )) < 0 ) {
error( "import %s failed: open_file failed", fname );
return ERR;
}
if ( (nrec = get_flen( fd )) < 0 ) {
error( "import %s failed: get_flen failed", fname );
close_file( fd );
return ERR;
}
/*
* read all IC35-records and note them
*/
message( "import \"%s\", read %d records", fname, nrec );
rval = OK;
for ( irec = 0; irec < nrec; ++irec ) {
if ( (ic35rec = new_ic35rec()) == NULL ) {
error( "import %s failed: no memory for ic35rec", fname );
rval = ERR;
break;
}
if ( read_frec( fd, irec, ic35rec ) < 0 ) {
rval = ERR;
break;
}
_put_ic35recs( ic35rec, IC35NOACT, NULL );
}
if ( rval != OK ) {
close_file( fd );
LPRINTF(( L_INFO, "importfile(fid=%02X) \"%s\" rval=ERR", fileid,fname ));
return rval;
}
/*
* compare all PIM-records with IC35-records, and do:
* - if PIM-record not in IC35, write it to IC35
* and write back record-ID from IC35 to PIM-record,
* - if different update IC35-record with PIM-record,
* - if same commit to IC35 if non-zero changeflag in IC35.
* mark all PIM-records CLEAN as they are now same as IC35.
* collect IC35 records with actions to do.
*/
n_write = n_update = n_commit = 0;
pim_rewind();
while ( (pimrec = pim_getrec( fileid )) != NULL ) {
if ( (recid = pim_recid( pimrec )) != 0 /* PIM record-ID on IC35 */
&& (ic35rec = _get_ic35recs( recid, NULL, NULL )) != NULL ) {
if ( pim_cmpic35rec( ic35rec, pimrec ) == 0 ) {
if ( ic35recchg( ic35rec ) == IC35_CLEAN ) {
del_ic35rec( ic35rec ); /* same as PIM, unchanged */
continue; /* no need for commit */
}
action = IC35COMMIT; /* same as PIM, commit it */
++n_commit;
} else {
action = IC35UPDATE; /* different, update rec */
++n_update;
}
} else { /* PIMrecord not on IC35 */
ic35rec = new_ic35rec();
if ( recid == FileRecId(FILEADDR,1) ) {
action = IC35UPDATE; /* must update owner-addr */
++n_update;
} else {
action = IC35WRITE; /* write new IC35 record */
++n_write;
}
}
pim_updic35rec( ic35rec, pimrec ); /* PIM update/new to IC35 */
_put_ic35recs( ic35rec, action, pimrec ); /* add action and PIMrec */
}
/*
* execute actions on IC35 records collected above.
* count records with no action, i.e. only existing
* on IC35, but not in PIMfile.
*/
message( "import \"%s\", write %d update %d commit %d records",
fname, n_write, n_update, n_commit );
ic35_not_in_PIM = 0;
while ( (ic35rec = _get_ic35recs( 0, &action, &pimrec )) != NULL ) {
rc = 0; actext = "";
switch ( action ) {
case IC35COMMIT:
actext = "commit";
rc = commit_frec( fd, ic35recid( ic35rec ) );
break;
case IC35UPDATE:
actext = "update";
rc = update_frec( fd, ic35rec );
break;
case IC35WRITE:
actext = "write";
rc = write_frec( fd, ic35rec );
break;
default:
++ic35_not_in_PIM;
continue;
}
if ( rc >= 0 ) { /* commit/update/write success */
if ( pimrec != NULL ) {
pim_set_recid( pimrec, ic35recid( ic35rec ) );
pim_set_recstat( pimrec, PIM_CLEAN );
}
} else { /* commit/update/write failed */
error( "import %s failed: %s_frec failed", fname, actext );
rval = ERR;
}
del_ic35rec( ic35rec );
}
_del_ic35recs();
if ( rval == OK )
rval = ic35_not_in_PIM; /* any IC35 records not in PIMfile */
close_file( fd );
LPRINTF(( L_INFO, "importfile(fid=%02X) \"%s\" rval=%d",
fileid, fname, rval ));
return rval;
}
static int
ic35import( char * devname, char * passwd )
{
int i, rc, rval;
bool ic35_same_as_PIM;
char ic35dtime[16+1];
if ( (rval = connect( devname, passwd, ic35dtime )) != 0 )
return rval;
set_oldic35dt( ic35dtime );
rval = OK;
ic35_same_as_PIM = TRUE;
for ( i = 0; i < sizeof(fileids)/sizeof(fileids[0]); ++i )
if ( (rc = importfile( fileids[i], ic35dtime )) != OK ) {
ic35_same_as_PIM = FALSE;
if ( rc < 0 ) {
rval = rc;
break;
}
}
if ( ic35_same_as_PIM ) {
get_newic35dt( ic35dtime );
WriteSysInfo( ic35dtime );
}
disconnect();
return rval;
}
/* run IC35 sync session
* ---------------------
* update PIMfile with IC35 changes (modify/delete) and vice versa
* - phase-0: initial export if PIMfile does not contains any records
* otherwise phase-3 below would delete all unmodified records on IC35,
* as they are regarded deleted from PIMfile.
* - phase-1a: update records modified/deleted on IC35 to PIMfile
* read all modified records from IC35, if unchanged in PIMfile:
* - delete from PIMfile if deleted on IC35,
* - update from IC35 to PIMfile if modified on IC35.
* note IC35-recID for commit (commit now would disturb read_mod_frec)
* conflict if record changed in IC35 AND also in PIMfile, resolve:
* - PIMfile overrides IC35: update from PIMrecord to IC35record
* will be done in next phase below (now would disturb read_mod_frec),
* - IC35 overrides PIMfile: update from IC35record to PIMrecord
* ??? ? add changed record on IC35/PIM to PIM/IC35 with conflict mark
* - phase-1b: commit handled IC35 changes to IC35
* commits noted above to avoid disturbing read_mod_frec, now do them.
* - phase-2: update records modified in PIMfile to IC35
* - if record exists on IC35, i.e. has record-ID,
* read record by ID from IC35, update with PIMrecord
* write record to IC35
* - if record is new in PIMfile (no record-ID)
* create IC35 record from PIMrecord, write to IC35
* and writeback new IC35 record-ID to PIMrecord
* - phase-3a: records deleted from PIMfile are detected by reading
* all records from IC35 and check if record in PIMfile
* ??? sanity check IC35 changeflags clean
* - PIMfile overrides IC35: note IC35-recID for delete
* (delete now would disturb read_frec)
* - IC35 overrides PIMfile: re-create PIMrecord from IC35 record
* - phase-3b: delete records on IC35
* deletes were noted above to avoid disturbing read_frec, now do them.
* now there should be no more pending changes neither in IC35 nor in PIM.
* write sysinfo (date+time) as now all IC35 records (shall) match PIMfile
*/
static int
syncfile( int fileid, char * ic35dtime )
{
char * fname;
bool initexp;
int fd, nrec, irec;
IC35REC * ic35rec;
void * pimrec;
ulong recid;
enum ic35op action;
int n_commit, n_delete;
int rc, rval;
if ( (fname = ic35fname( fileid )) == NULL ) {
error( "sync failed: bad fileid %02X", fileid );
return ERR;
}
/*
* phase-0: initial export if PIMfile does not contains any records
* otherwise phase-3 below would delete all unmodified records on IC35
*/
initexp = FALSE;
pim_rewind();
if ( pim_getrec( fileid ) == NULL ) {
message( "sync \"%s\", no PIM records: initial export", fname );
if ( (rval = exportfile( fileid )) != OK )
return rval;
initexp = TRUE;
}
LPRINTF(( L_INFO, "syncfile(fid=%02X) \"%s\" ..", fileid, fname ));
if ( (fd = open_file( ic35fname( fileid ) )) < 0 ) {
error( "sync %s failed: open_file failed", fname );
return ERR;
}
/*
* phase-1a: update records modified/deleted on IC35 to PIMfile
* read all modified records from IC35, if unchanged in PIMfile:
* - delete from PIMfile if deleted on IC35,
* - update from IC35 to PIMfile if modified on IC35.
* note IC35-recID for commit (commit now would disturb read_mod_frec)
* conflict if record changed in IC35 AND also in PIMfile, resolve:
* - PIMfile overrides IC35: update from PIMrecord to IC35record
* will be done in next phase below (now would disturb read_mod_frec),
* - IC35 overrides PIMfile: update from IC35record to PIMrecord
* ? add changed record on IC35/PIM to PIM/IC35 with conflict mark ???
*/
if ( (nrec = get_mod_flen( fd )) < 0 ) {
error( "sync %s failed: get_mod_flen failed", fname );
close_file( fd );
return ERR;
}
message( "sync \"%s\", read %d modified records%s",
fname, nrec, nrec > 0 ? ", update PIM" : "" );
n_commit = 0;
rval = OK;
for ( irec = 0; irec < nrec; ++irec ) {
if ( (ic35rec = new_ic35rec()) == NULL ) {
error( "sync %s failed: no memory", fname );
rval = ERR;
break;
}
if ( read_mod_frec( fd, ic35rec ) < 0 ) {
error( "sync %s failed: read_mod_frec failed", fname );
rval = ERR;
break;
}
if ( (pimrec = pim_getrec_byID( ic35recid( ic35rec ) )) == NULL
|| pim_recstat( pimrec ) == PIM_CLEAN ) {
switch ( ic35recchg( ic35rec ) ) {
case IC35_NEW:
case IC35_MOD:
pim_putic35rec( ic35rec );
break;
case IC35_DEL:
if ( pimrec )
pim_delrec( pimrec );
break;
}
_put_ic35recs( ic35rec, IC35COMMIT, NULL );
++n_commit;
} else {
; /*??? CONFLICT: changed on both sides */
}
}
/*
* phase-1b: commit handled IC35 changes to IC35
* commits noted above to avoid disturbing read_mod_frec, now do them.
*/
if ( rval == OK && n_commit > 0 ) {
message( "sync \"%s\", commit %d IC35 records", fname, n_commit );
while ( (ic35rec = _get_ic35recs( 0, &action, NULL )) != NULL ) {
if ( action == IC35COMMIT
&& commit_frec( fd, ic35recid( ic35rec ) ) < 0 ) {
error( "sync %s failed: commit_frec failed", fname );
rval = ERR;
break;
}
del_ic35rec( ic35rec );
}
}
_del_ic35recs();
if ( rval != OK ) {
close_file( fd );
LPRINTF(( L_INFO, "syncfile(fid=%02X) \"%s\" rval=ERR", fileid,fname ));
return rval;
}
/*
* if initial export was done, update from PIM to IC35 and
* check records removed from PIM and delete is not needed.
*/
if ( initexp ) {
close_file( fd );
LPRINTF(( L_INFO, "syncfile(fid=%02X) \"%s\" rval=OK", fileid, fname ));
return rval;
}
/*
* phase-2: update records modified in PIMfile to IC35
* - if record exists on IC35, i.e. has record-ID,
* read record by ID from IC35, update with PIMrecord
* write record to IC35
* - if record is new in PIMfile (no record-ID)
* create IC35 record from PIMrecord, write to IC35
* and writeback new IC35 record-ID to PIMrecord
*/
if ( (ic35rec = new_ic35rec()) == NULL ) {
close_file( fd );
error( "sync %s failed: no memory", fname );
return ERR;
}
message( "sync \"%s\", update IC35", fname );
pim_rewind();
while ( rval == OK && (pimrec = pim_getrec( fileid )) != NULL ) {
switch ( pim_recstat( pimrec ) ) {
case PIM_CLEAN:
continue;
case PIM_DEL:
if ( (recid = pim_recid( pimrec )) != 0 ) {
if ( delete_frec( fd, recid ) >= 0 ) {
pim_delrec( pimrec );
} else {
error( "sync %s failed: delete_frec failed", fname );
rval = ERR;
}
}
continue;
default:
error( "bad PIM record status: %d", pim_recstat( pimrec ) );
/* full through and handle as PIM_DIRTY */
case PIM_DIRTY:
if ( (recid = pim_recid( pimrec )) != 0 ) { /* PIMrec on IC35 */
if ( (rc = read_id_frec( fd, recid, ic35rec )) < 0 ) {
error( "sync %s failed: read_id_frec failed", fname );
rval = ERR;
break;
}
if ( rc > 0 ) { /* PIMrec found on IC35 */
pim_updic35rec( ic35rec, pimrec );
if ( update_frec( fd, ic35rec ) >= 0 ) {
pim_set_recstat( pimrec, PIM_CLEAN );
} else {
error( "sync %s failed: update_frec failed", fname );
rval = ERR;
}
}
break;
} /* PIMrecord not on IC35 */
set_ic35recdata( ic35rec, NULL, 0 );
pim_updic35rec( ic35rec, pimrec );
if ( write_frec( fd, ic35rec ) >= 0 ) {
pim_set_recid( pimrec, ic35recid( ic35rec ) );
pim_set_recstat( pimrec, PIM_CLEAN );
} else {
error( "sync %s failed: write_frec failed", fname );
rval = ERR;
}
break;
}
}
del_ic35rec( ic35rec ); ic35rec = NULL;
if ( rval != OK ) {
close_file( fd );
LPRINTF(( L_INFO, "syncfile(fid=%02X) \"%s\" rval=ERR", fileid,fname ));
return rval;
}
/*
* phase-3a: records deleted from PIMfile are detected by reading
* all records from IC35 and check if record in PIMfile
* ? sanity check IC35 changeflags clean ???
* - PIMfile overrides IC35: note IC35-recID for delete
* (delete now would disturb read_frec)
* - IC35 overrides PIMfile: re-create PIMrecord from IC35 record
*/
if ( (nrec = get_flen( fd )) < 0 ) {
error( "sync %s failed: get_flen failed", fname );
close_file( fd );
return ERR;
}
message( "sync \"%s\", read %d records, check PIM deleted", fname, nrec );
n_delete = 0;
for ( irec = 0; irec < nrec; ++irec ) {
if ( (ic35rec = new_ic35rec()) == NULL ) {
error( "sync %s failed: no memory", fname );
rval = ERR;
break;
}
if ( read_frec( fd, irec, ic35rec ) < 0 ) {
error( "sync %s failed: read_frec failed", fname );
rval = ERR;
break;
}
if ( pim_getrec_byID( ic35recid( ic35rec ) ) ) {
del_ic35rec( ic35rec );
continue;
}
/*??? sanity check ic35recchg() == 0 ? */
/*??? if PIM overrides IC35 */
_put_ic35recs( ic35rec, IC35DELETE, NULL );
++n_delete;
/*??? if IC35 overrides PIM */
/*??? pim_putic35rec( ic35rec ); */
}
/*
* phase-3b: delete records on IC35
* deletes were noted above to avoid disturbing read_frec, now do them.
*/
if ( rval == OK && n_delete ) {
message( "sync \"%s\", delete %d IC35 records", fname, n_delete );
while ( (ic35rec = _get_ic35recs( 0, &action, NULL )) != NULL ) {
if ( action == IC35DELETE
&& delete_frec( fd, ic35recid( ic35rec ) ) < 0 ) {
error( "sync %s failed: delete_frec failed", fname );
rval = ERR;
break;
}
del_ic35rec( ic35rec );
}
}
_del_ic35recs();
close_file( fd );
LPRINTF(( L_INFO, "syncfile(fid=%02X) \"%s\" rval=%d",
fileid, fname, rval ));
return rval;
}
static int
ic35sync( char * devname, char * passwd )
{
int i, rval;
char ic35dtime[16+1];
if ( (rval = connect( devname, passwd, ic35dtime )) != 0 )
return rval;
set_oldic35dt( ic35dtime );
for ( i = 0; i < sizeof(fileids)/sizeof(fileids[0]); ++i ) {
if ( (rval = syncfile( fileids[i], ic35dtime )) != OK )
break;
}
if ( rval == OK ) {
get_newic35dt( ic35dtime );
WriteSysInfo( ic35dtime );
}
disconnect();
return rval;
}
/* -------------------- M A I N - program ----------------------------- */
static void
versinfo( void )
{
printf( "IC35sync for GNU/Linux %s (%s)\n", pkgvers, pkgdate );
printf( "%s\n", bldinfo );
printf(
"Copyright (C) 2000,2001 Thomas Schulz\n"
"This is free software; see the GNU General Public Licence version 2 in\n"
"the file named COPYING for copying conditions. There is NO warranty.\n"
);
}
static void
usage( void )
{
static char * usetext[] = {
"usage: ic35sync [option..] command [pimfile..]",
"commands are:",
" sync synchronize IC35 with pimfile(s) data",
" export read all data from IC35 and write to pimfile(s)",
" import write to IC35 all data read from pimfile(s)",
" status report IC35 status (no pimfile access)",
"pimfile contains local Personal Information Management data,",
"e.g. in vCard/vCalendar format.",
"options in short and long form are:",
" -d DEV --device=DEV serial device with IC35 connected, default /dev/ic35",
" -p TEXT --password=TEXT password TEXT on IC35, default none",
" -f FORM --format=FORM format of pimfile(s), FORM and default pimfile(s):",
" vca (default) vCard,vCalendar,Memo, ic35.vcard ic35.vcal ic35.memo",
" txt (export only) plain text, ic35.txt",
" bin raw binary data, ic35.bin",
#ifndef NO_LOGSIM
" -l FILE --logfile=FILE log communications to FILE, default no logging",
" -s FILE --simfile=FILE simulate communication with IC35 using FILE",
" (create simulation FILE from logfile with 'ic35log')",
#endif
" -V --version show version information and exit",
" -h --help show this help and exit",
NULL
};
char ** lptr;
for ( lptr = usetext; *lptr != NULL; ++lptr )
printf( "%s\n", *lptr );
}
int
main( int argc, char *argv[] )
{
static struct option const long_opts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "device", required_argument, NULL, 'd' },
{ "password", required_argument, NULL, 'p' },
{ "format", required_argument, NULL, 'f' },
#ifndef NO_LOGSIM
{ "logfile", required_argument, NULL, 'l' },
{ "simfile", required_argument, NULL, 's' },
#endif
{ NULL, 0, NULL, 0 }
};
char * passwd = "";
char * devname = "/dev/ic35";
char * pimfmtstr = "vca";
char * command = NULL;
char * pimaddrfname = NULL;
char * pimvcalfname = NULL;
char * pimmemofname = NULL;
#ifndef NO_LOGSIM
char * logfname = NULL;
char * simfname = NULL;
#endif
int rval;
/*
* parse command line
*/
for ( ; ; ) {
switch ( getopt_long( argc, argv,
#ifndef NO_LOGSIM
"l:s:"
#endif
"d:p:f:hV", long_opts, NULL ) ) {
default:
fprintf( stderr, "use 'ic35sync --help' for more information\n" );
return 1;
case 'h': /* show Help and exit */
usage();
return 0;
case 'V': /* show Version and exit */
versinfo();
return 0;
case 'd': /* serial Device where IC35 */
devname = optarg;
continue;
case 'p': /* password on IC35 */
passwd = optarg;
continue;
case 'f': /* format of PIMfile */
pimfmtstr = optarg;
continue;
#ifndef NO_LOGSIM
case 'l': /* communication logfile */
logfname = optarg;
continue;
case 's': /* simulate: no communication */
simfname = optarg;
continue;
#endif/*NO_LOGSIM*/
case -1: /* end of options */
break;
}
break;
}
if ( argc < optind+1 ) {
error( "missing command\n"
"use 'ic35sync --help' for more information" );
return 1;
}
command = argv[optind];
/*
* initial info to logfile: date,time, version, command line
* if 'logfname' is NULL or empty, nothing will be logged.
*/
LOG_INIT(( logfname, "ic35sync", 0 ));
LOG_PROGINFO(( "ic35sync", pkgvers, pkgdate, bldinfo ));
LOG_ARGSINFO(( argc, argv ));
/*
* setup simulated communication if requested
*/
COM_SIMINIT(( simfname ));
/*
* status command does not use pimfile(s)
*/
if ( strcmp( command, "status" ) == 0 ) {
rval = ic35status( devname, passwd ) == OK ? 0 : 1;
LOG_CLOSE(());
return rval;
}
/*
* defaults for filenames are:
* - no filename
* use defaults depending on format
* - text format ic35.txt
* - binary format ic35.bin
* - vCard,vCal format ic35.vcard, ic35.vcal, ic35.memo
* - 1 filename
* Addresses, Schedule,ToDo, Memo all in 1 file
* - 2 filenames
* Addresses to 1st file, Schedule,ToDo,Memo to 2nd file
* - 3 filenames
* Addresses to 1st file, Schedule,ToDo to 2nd, Memo to 3rd
*/
if ( set_pim_format( pimfmtstr ) != OK ) {
error( "unknown format: %s", pimfmtstr );
return 1;
}
argv += optind, argc -= optind; /* skip to non-option arguments */
switch ( argc ) {
default:
error( "max. 3 pimfiles supported, have %d", argc - 1 );
return 1;
case 4: /* 3 filenames */
pimmemofname = argv[3];
/* fall through */
case 3: /* 2 filenames */
pimvcalfname = argv[2];
/* fall through */
case 2: /* 1 filename */
pimaddrfname = argv[1];
break;
case 1: /* no filename */
switch ( pim_format() ) {
case PIM_TXT:
pimaddrfname = "ic35.txt";
break;
case PIM_BIN:
pimaddrfname = "ic35.bin";
break;
case PIM_VCA:
pimaddrfname = "ic35.vcard";
pimvcalfname = "ic35.vcal";
pimmemofname = "ic35.memo";
break;
}
break;
}
if ( pim_open( pimaddrfname, pimvcalfname, pimmemofname ) != OK ) {
error( "failed to open pimfile(s): %s %s %s\n",
pimaddrfname,
pimvcalfname ? pimvcalfname : "",
pimmemofname ? pimmemofname : "" );
return 1;
}
/*
* process command
*/
if ( strcmp( command, "export" ) == 0 ) {
rval = ic35export( devname, passwd ) == OK ? 0 : 1;
} else if ( strcmp( command, "import" ) == 0 ) {
rval = ic35import( devname, passwd ) == OK ? 0 : 1;
} else if ( strcmp( command, "sync" ) == 0 ) {
rval = ic35sync( devname, passwd ) == OK ? 0 : 1;
} else {
error( "unsupported command: %s", command );
rval = 1;
}
pim_close();
LOG_CLOSE(());
return rval;
}