/************************************************************************ * 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 /* printf(), .. */ #include /* strcmp(), .. */ #include /* getopt(), optarg, .. */ #include /* 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; }