723 lines
20 KiB
C
723 lines
20 KiB
C
/************************************************************************
|
||
* Copyright (C) 2000,2001 Thomas Schulz *
|
||
* */
|
||
static char rcsid[] =
|
||
"$Id: vcaconv.c,v 1.17 2001/02/17 20:56:49 tsch Rel $"; /*
|
||
* *
|
||
* vCard,vCalendar conversion *
|
||
* *
|
||
*************************************************************************
|
||
* *
|
||
* ??? is "fixme" mark: sections of code needing fixes *
|
||
* *
|
||
* for usage run vcaconv -h or see function usage() below. *
|
||
* *
|
||
************************************************************************/
|
||
|
||
#include <stdio.h> /* printf(), .. */
|
||
#include <string.h> /* strcasecmp(), .. */
|
||
#include <getopt.h> /* getopt(), optarg, .. */
|
||
#include <ctype.h> /* isdigit() */
|
||
#include <time.h> /* struct tm, time() .. */
|
||
|
||
#include "vcc.h" /* VObject, .. */
|
||
#include "syntrans.h" /* FILEADDR, .. */
|
||
#include "dataio.h" /* ic35addr_to_vcard()..*/
|
||
#include "vcutil.h" /* vca_type(), .. */
|
||
#include "util.h" /* uchar, .. */
|
||
NOTUSED(rcsid)
|
||
|
||
|
||
extern char * pkgvers; /* these are all */
|
||
extern char * pkgdate; /* in versinfo.c, which is */
|
||
extern char * bldinfo; /* auto-generated by Makefile */
|
||
|
||
|
||
/* get VObject's string value (dupStr()'d)
|
||
* --------------------------
|
||
*/
|
||
static char *
|
||
dupStrValue( VObject * vobj, const char * id )
|
||
{
|
||
char * strval;
|
||
|
||
if ( (strval = dupStringValue( vobj, id )) == NULL )
|
||
strval = dupStr( "", 0 );
|
||
return strval;
|
||
}
|
||
|
||
|
||
/* ==================================================== */
|
||
/* parse VObject list from vCard/vCal file */
|
||
/* ==================================================== */
|
||
|
||
/* parse error handler
|
||
* -------------------
|
||
*/
|
||
static bool _vca_error;
|
||
static char * _vca_fname;
|
||
|
||
static void
|
||
_vca_errmsg( char * msg ) /* mimeErrorHandler for Parse_MIME_FromFile() */
|
||
{
|
||
error( "vcafile \"%s\": %s", _vca_fname, msg );
|
||
_vca_error = TRUE;
|
||
}
|
||
|
||
/* parse vCard,vCal file
|
||
* ---------------------
|
||
*/
|
||
static VObject *
|
||
vca_parse( char * fname )
|
||
{
|
||
FILE * infp;
|
||
VObject * vlist;
|
||
|
||
if ( fname && *fname && strcmp( fname, "-" ) != 0 ) {
|
||
if ( (infp = fopen( fname, "r" )) == NULL ) {
|
||
error( "cannot open vcafile: %s", fname );
|
||
return NULL;
|
||
}
|
||
} else {
|
||
fname = "(stdin)";
|
||
infp = stdin;
|
||
}
|
||
registerMimeErrorHandler( _vca_errmsg );
|
||
_vca_error = FALSE;
|
||
_vca_fname = fname;
|
||
vlist = Parse_MIME_FromFile( infp );
|
||
if ( _vca_error ) {
|
||
cleanVObjects( vlist );
|
||
vlist = NULL;
|
||
}
|
||
if ( infp != stdin )
|
||
fclose( infp );
|
||
return vlist;
|
||
}
|
||
|
||
|
||
/* ==================================== */
|
||
/* sort list of VObjects */
|
||
/* ==================================== */
|
||
|
||
/* compare property of VObjects
|
||
* ----------------------------
|
||
*/
|
||
static int
|
||
_compare_vprop( const char * id, VObject * vobj1, VObject * vobj2 )
|
||
{
|
||
int cmp;
|
||
|
||
if ( !( id && *id )
|
||
|| (vobj1 == NULL && vobj2 == NULL) )
|
||
return 0;
|
||
if ( vobj1 == NULL )
|
||
return -1;
|
||
if ( vobj2 == NULL )
|
||
return +1;
|
||
|
||
if ( strcasecmp( id, VCNameProp ) == 0 ) {
|
||
VObject * vprop1 = isAPropertyOf( vobj1, id );
|
||
VObject * vprop2 = isAPropertyOf( vobj2, id );
|
||
if ( (cmp = _compare_vprop( VCFamilyNameProp, vprop1, vprop2 )) != 0 )
|
||
return cmp;
|
||
else
|
||
return _compare_vprop( VCGivenNameProp, vprop1, vprop2 );
|
||
}
|
||
if ( strcasecmp( id, XPilotIdProp ) == 0 ) {
|
||
ulong val1 = LongValue( vobj1, id );
|
||
ulong val2 = LongValue( vobj2, id );
|
||
if ( val1 < val2 )
|
||
return -1;
|
||
if ( val1 > val2 )
|
||
return +1;
|
||
return 0;
|
||
}
|
||
if ( strcasecmp( id, VCLastModifiedProp ) == 0
|
||
|| strcasecmp( id, VCLastRevisedProp ) == 0
|
||
|| strcasecmp( id, VCDTstartProp ) == 0
|
||
|| strcasecmp( id, VCDTendProp ) == 0 ) {
|
||
time_t time1 = isodtime_to_unixtime( vobj1, id );
|
||
time_t time2 = isodtime_to_unixtime( vobj2, id );
|
||
if ( time1 < time2 )
|
||
return -1;
|
||
if ( time1 > time2 )
|
||
return +1;
|
||
return 0;
|
||
}
|
||
{
|
||
char * str1 = dupStrValue( vobj1, id );
|
||
char * str2 = dupStrValue( vobj2, id );
|
||
cmp = strcmp( str1, str2 );
|
||
deleteStr( str1 );
|
||
deleteStr( str2 );
|
||
return cmp;
|
||
}
|
||
}
|
||
|
||
/* compare VObjects for sorting
|
||
* ----------------------------
|
||
*/
|
||
static int
|
||
_compare_vobj( const void * pvobj1, const void * pvobj2 )
|
||
{
|
||
VObject * vobj1 = *(VObject**)pvobj1;
|
||
VObject * vobj2 = *(VObject**)pvobj2;
|
||
int type1 = vca_type( vobj1 );
|
||
int type2 = vca_type( vobj2 );
|
||
int cmp;
|
||
|
||
if ( type1 < type2 )
|
||
return -1;
|
||
else if ( type1 > type2 )
|
||
return +1;
|
||
|
||
switch ( type1 ) {
|
||
case VCARD: /* addr: Name, REV, */
|
||
if ( (cmp = _compare_vprop( VCNameProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
if ( (cmp = _compare_vprop( VCLastRevisedProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
break;
|
||
case VMEMO: /* memo: subject, */
|
||
if ( (cmp = _compare_vprop( VCSummaryProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
if ( (cmp = _compare_vprop( VCLastModifiedProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
break;
|
||
case VEVENT: /* vcal.sched: DTSTART, subject, rev, */
|
||
if ( (cmp = _compare_vprop( VCDTstartProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
if ( (cmp = _compare_vprop( VCSummaryProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
if ( (cmp = _compare_vprop( VCLastModifiedProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
break;
|
||
case VTODO: /* vcal.todo: DTSTART, subject, rev, */
|
||
if ( (cmp = _compare_vprop( VCDueProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
if ( (cmp = _compare_vprop( VCSummaryProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
if ( (cmp = _compare_vprop( VCLastModifiedProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
break;
|
||
case VCAL: /* multiple vCAL ? VERSION, PRODID */
|
||
if ( (cmp = _compare_vprop( VCVersionProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
return _compare_vprop( VCProdIdProp, vobj1, vobj2 );
|
||
}
|
||
/* same with above compares: X-PILOTID, UID */
|
||
if ( (cmp = _compare_vprop( XPilotIdProp, vobj1, vobj2 )) != 0 )
|
||
return cmp;
|
||
return _compare_vprop( VCUniqueStringProp, vobj1, vobj2 );
|
||
}
|
||
|
||
/* sort VObject's property list
|
||
* ----------------------------
|
||
*/
|
||
struct propseq {
|
||
int seq;
|
||
char * id;
|
||
};
|
||
static struct propseq _propseq[] = {
|
||
{ -6, VCNameProp },
|
||
{ -5, VCDTstartProp },
|
||
{ -4, VCDTendProp },
|
||
{ -3, VCDueProp },
|
||
{ -2, VCSummaryProp },
|
||
{ -1, VCDescriptionProp },
|
||
{ +1, VCCategoriesProp },
|
||
{ +2, VCDCreatedProp },
|
||
{ +3, VCLastModifiedProp },
|
||
{ +4, VCLastRevisedProp },
|
||
{ +5, VCUniqueStringProp },
|
||
{ +6, XPilotIdProp },
|
||
{ +7, XPilotStatusProp },
|
||
{ 0, NULL }
|
||
};
|
||
static int
|
||
_propid_seq( const char * id )
|
||
{
|
||
struct propseq * pseq;
|
||
|
||
for ( pseq = _propseq; pseq->id; ++pseq )
|
||
if ( strcasecmp( id, pseq->id ) == 0 )
|
||
return pseq->seq;
|
||
return 0;
|
||
}
|
||
static int /* compare properties for sorting */
|
||
_compare_props( const void * pvprop1, const void * pvprop2 )
|
||
{
|
||
VObject * vprop1 = *(VObject**)pvprop1;
|
||
VObject * vprop2 = *(VObject**)pvprop2;
|
||
const char *id1, *id2;
|
||
int seq1, seq2;
|
||
char *str1, *str2;
|
||
int cmp;
|
||
|
||
seq1 = _propid_seq( id1 = vObjectName( vprop1 ) );
|
||
seq2 = _propid_seq( id2 = vObjectName( vprop2 ) );
|
||
if ( seq1 < seq2 )
|
||
return -1;
|
||
if ( seq1 > seq2 )
|
||
return +1;
|
||
if ( (cmp = strcasecmp( id1, id2 )) == 0 ) {
|
||
cmp = strcmp( str1 = dupStrValue( vprop1, NULL ),
|
||
str2 = dupStrValue( vprop2, NULL ) );
|
||
deleteStr( str1 );
|
||
deleteStr( str2 );
|
||
}
|
||
return cmp;
|
||
}
|
||
static void /* sort VObject's property list */
|
||
vobjsort( VObject * vobj )
|
||
{
|
||
size_t n, i;
|
||
VObjectIterator iter;
|
||
VObject ** vproptab;
|
||
VObject * vprop;
|
||
|
||
n = 0; /* count number of properties, alloc table */
|
||
initPropIterator( &iter, vobj );
|
||
while ( moreIteration( &iter ) ) {
|
||
(void)nextVObject( &iter );
|
||
++n;
|
||
}
|
||
vproptab = malloc ( n * sizeof(vproptab[0]) );
|
||
if ( vproptab == NULL )
|
||
return;
|
||
/* build table of property ptrs and sort */
|
||
i = 0;
|
||
initPropIterator( &iter, vobj );
|
||
while ( i < n && moreIteration( &iter ) )
|
||
vproptab[i++] = nextVObject( &iter );
|
||
qsort( vproptab, n, sizeof(vproptab[0]), _compare_props );
|
||
/* rebuild property list in sorted sequ */
|
||
for ( i = 0; i < n; ++i )
|
||
if ( (vprop = delProp( vobj, vproptab[i] )) != NULL )
|
||
addVObjectProp( vobj, vprop );
|
||
|
||
free( vproptab );
|
||
}
|
||
|
||
/* sort VObject list
|
||
* -----------------
|
||
*/
|
||
static int
|
||
vca_sort( VObject ** vlist )
|
||
{
|
||
size_t n, i;
|
||
VObject * vcal;
|
||
VObject ** vobjtab;
|
||
VObject * vobj;
|
||
VObjectIterator iter;
|
||
|
||
/* count number of VObjects, alloc table */
|
||
n = 0; vcal = NULL;
|
||
for ( vobj = *vlist; vobj !=NULL; vobj = nextVObjectInList( vobj ) ) {
|
||
++n;
|
||
if ( vca_type( vobj ) == VCAL ) {
|
||
if ( vcal == NULL )
|
||
vcal = vobj;
|
||
initPropIterator( &iter, vobj );
|
||
while ( moreIteration( &iter ) ) {
|
||
(void)nextVObject( &iter );
|
||
++n;
|
||
}
|
||
}
|
||
}
|
||
vobjtab = malloc ( n * sizeof(vobjtab[0]) );
|
||
if ( vobjtab == NULL )
|
||
return ERR;
|
||
|
||
/* build table of VObject ptrs and sort */
|
||
i = 0;
|
||
for ( vobj = *vlist; vobj !=NULL; vobj = nextVObjectInList( vobj ) ) {
|
||
vobjtab[i++] = vobj;
|
||
if ( vca_type( vobj ) == VCAL ) {
|
||
initPropIterator( &iter, vobj );
|
||
while ( moreIteration( &iter ) )
|
||
vobjtab[i++] = nextVObject( &iter );
|
||
}
|
||
}
|
||
qsort( vobjtab, n, sizeof(vobjtab[0]), _compare_vobj );
|
||
|
||
/* rebuild VObject list in sorted sequ */
|
||
for ( i = 0; i < n; ++i ) {
|
||
vobj = vobjtab[i];
|
||
switch ( vca_type( vobj ) ) {
|
||
case VCARD:
|
||
case VMEMO:
|
||
vobjsort( vobj ); /* sort VObject's property list */
|
||
/* fall thru */
|
||
case VCAL:
|
||
vobj = delList( vlist, vobj );
|
||
if ( vobj != NULL )
|
||
addList( vlist, vobj );
|
||
break;
|
||
case VEVENT:
|
||
case VTODO:
|
||
if ( vcal == NULL )
|
||
break;
|
||
vobjsort( vobj ); /* sort VObject's property list */
|
||
vobj = delProp( vcal, vobj );
|
||
if ( vobj != NULL )
|
||
addVObjectProp( vcal, vobj );
|
||
break;
|
||
}
|
||
}
|
||
free( vobjtab );
|
||
|
||
return OK;
|
||
}
|
||
|
||
|
||
/* ==================================== */
|
||
/* create telbook for handy */
|
||
/* ==================================== */
|
||
|
||
static bool
|
||
hasCategory( VObject * vobj, char * wanted )
|
||
{
|
||
char * categories;
|
||
char * category;
|
||
|
||
if ( !( vobj && wanted && *wanted ) )
|
||
return FALSE;
|
||
categories = dupStrValue( vobj, VCCategoriesProp );
|
||
for ( category = strtok( categories, ";" );
|
||
category; category = strtok( NULL, ";" ) )
|
||
if ( strcasecmp( category, wanted ) == 0 )
|
||
break;
|
||
deleteStr( categories );
|
||
return (bool)( category != NULL );
|
||
}
|
||
static char *
|
||
NameValue( VObject * vobj, const char * type )
|
||
{
|
||
VObject * vprop;
|
||
char * namestr;
|
||
|
||
if ( !( vobj && type && *type )
|
||
|| (vprop = isAPropertyOf( vobj, VCNameProp )) == NULL )
|
||
return NULL;
|
||
if ( (namestr = dupStrValue( vprop, type )) && *namestr )
|
||
return namestr;
|
||
deleteStr( namestr );
|
||
if ( (namestr = dupStrValue( vprop, VCFamilyNameProp )) && *namestr )
|
||
return namestr;
|
||
deleteStr( namestr );
|
||
return dupStrValue( vprop, VCGivenNameProp );
|
||
}
|
||
static char *
|
||
TelnoValue( VObject * vobj, const char * type )
|
||
{
|
||
VObjectIterator iter, teliter;
|
||
VObject * vprop;
|
||
VObject * teltype;
|
||
VObject * telpref;
|
||
VObject * teldflt;
|
||
char * telstr, *src, *dst;
|
||
|
||
if ( !( vobj && type && *type ) )
|
||
return NULL;
|
||
teltype = telpref = teldflt = NULL;
|
||
initPropIterator( &iter, vobj );
|
||
while ( moreIteration( &iter ) ) {
|
||
vprop = nextVObject( &iter );
|
||
if ( strcmp( vObjectName( vprop ), VCTelephoneProp ) != 0 )
|
||
continue;
|
||
if ( teltype == NULL
|
||
&& isAPropertyOf( vprop, type ) )
|
||
teltype = vprop;
|
||
if ( telpref == NULL
|
||
&& isAPropertyOf( vprop, VCPreferredProp ) )
|
||
telpref = vprop;
|
||
initPropIterator( &teliter, vprop );
|
||
if ( teldflt == NULL
|
||
&& ! moreIteration( &teliter ) )
|
||
teldflt = vprop;
|
||
}
|
||
telstr = dupStrValue( teltype ? teltype :
|
||
( telpref ? telpref : teldflt ), NULL );
|
||
if ( (dst = src = telstr) && *telstr ) {
|
||
do {
|
||
if ( (src == telstr && *src == '+') /* international +49 */
|
||
|| isdigit( *src ) ) /* skip separators, because */
|
||
*dst++ = *src; /* handy does not like them */
|
||
} while ( *src++ );
|
||
}
|
||
return telstr;
|
||
}
|
||
|
||
/*
|
||
* special categories for handy telbook:
|
||
* S35SIM pre-installed entries from S35i
|
||
* HANDY created for import into handy
|
||
* special conversions
|
||
* - vCards for handy have only VCNameProp.VCFamilyNameProp and
|
||
* VCTelephoneProp with VCCellularProp attribute
|
||
* for category "Business" and other derive from VCFamilyNameProp
|
||
* for category "Personal" derive from VCGivenNameProp
|
||
* - for multiple telnos make multiple vCards with append to name:
|
||
* Business: append none, "-priv", "-mobil" for WORK, HOME, CELL
|
||
* Personal: append "-Buero", none, "-mobil" for WORK, HOME, CELL
|
||
* - for category "Personal" make "VIP" entries by appending "!"
|
||
*/
|
||
static VObject *
|
||
new_handycard( char * name, char * suffix, char * telno )
|
||
{
|
||
VObject * vcard;
|
||
char namebuff[18+1];
|
||
time_t tnow;
|
||
struct tm * ptm;
|
||
char isodtime[24];
|
||
|
||
if ( !(name && *name)
|
||
|| !(telno && *telno)
|
||
|| (vcard = newVObject( VCCardProp )) == NULL )
|
||
return NULL;
|
||
|
||
strncat( strcpy( namebuff, "" ), name, sizeof(namebuff)-1 );
|
||
if ( suffix && *suffix ) {
|
||
namebuff[ sizeof(namebuff)-1 - 4 ] = '\0';
|
||
strncat( namebuff, suffix, sizeof(namebuff)-1 - strlen(namebuff) );
|
||
}
|
||
addPropValue( vcard, VCFullNameProp, namebuff );
|
||
addPropValue( addProp( vcard, VCNameProp ), VCFamilyNameProp, namebuff );
|
||
|
||
addProp( addPropValue( vcard, VCTelephoneProp, telno ), VCCellularProp );
|
||
addPropValue( vcard, VCCategoriesProp, "HANDY" );
|
||
|
||
tnow = time( NULL );
|
||
ptm = localtime( &tnow );
|
||
strftime( isodtime, sizeof(isodtime), "%Y-%m-%dT%H:%M:%S", ptm );
|
||
addPropValue( vcard, VCLastRevisedProp, isodtime );
|
||
|
||
return vcard;
|
||
}
|
||
static int
|
||
vcard_to_handy( VObject ** vlist )
|
||
{
|
||
VObject * vobj;
|
||
VObject * vcard;
|
||
VObject * vdel;
|
||
VObject * handylist;
|
||
VObject * vnext;
|
||
char * name, *tel1, *tel2;
|
||
|
||
vdel = handylist = NULL;
|
||
for ( vobj = *vlist; vobj !=NULL; vobj = nextVObjectInList( vobj ) ) {
|
||
if ( vca_type( vobj ) != VCARD )
|
||
continue;
|
||
if ( hasCategory( vobj, "HANDY" ) ) {
|
||
if ( vdel )
|
||
cleanVObject( vdel );
|
||
vdel = delList( vlist, vobj );
|
||
continue;
|
||
}
|
||
if ( hasCategory( vobj, "NOTHANDY" ) )
|
||
continue;
|
||
|
||
if ( hasCategory( vobj, "S35SIM" ) ) {
|
||
name = NameValue( vobj, VCGivenNameProp );
|
||
if ( (tel1 = TelnoValue( vobj, VCCellularProp )) && *tel1
|
||
&& (vcard = new_handycard( name, NULL, tel1 )) != NULL )
|
||
addList( &handylist, vcard );
|
||
deleteStr( tel1 );
|
||
deleteStr( name );
|
||
|
||
} else if ( hasCategory( vobj, "Personal" ) ) {
|
||
name = NameValue( vobj, VCGivenNameProp );
|
||
if ( (tel1 = TelnoValue( vobj, VCHomeProp )) && *tel1
|
||
&& (vcard = new_handycard( name, "!", tel1 )) != NULL )
|
||
addList( &handylist, vcard );
|
||
|
||
if ( (tel2 = TelnoValue( vobj, VCWorkProp )) && *tel2
|
||
&& strcmp( tel1, tel2 ) != 0
|
||
&& (vcard = new_handycard( name, "-B<>ro!", tel2 )) != NULL )
|
||
addList( &handylist, vcard );
|
||
deleteStr( tel2 );
|
||
|
||
if ( (tel2 = TelnoValue( vobj, VCCellularProp )) && *tel2
|
||
&& strcmp( tel1, tel2 ) != 0
|
||
&& (vcard = new_handycard( name, "-mobil!", tel2 )) != NULL )
|
||
addList( &handylist, vcard );
|
||
deleteStr( tel2 );
|
||
deleteStr( tel1 );
|
||
deleteStr( name );
|
||
|
||
} else { /* Business etc. */
|
||
name = NameValue( vobj, VCFamilyNameProp );
|
||
if ( (tel1 = TelnoValue( vobj, VCWorkProp )) && *tel1
|
||
&& (vcard = new_handycard( name, NULL, tel1 )) != NULL )
|
||
addList( &handylist, vcard );
|
||
|
||
if ( (tel2 = TelnoValue( vobj, VCHomeProp )) && *tel2
|
||
&& strcmp( tel1, tel2 ) != 0
|
||
&& (vcard = new_handycard( name, "-priv", tel2 )) != NULL )
|
||
addList( &handylist, vcard );
|
||
deleteStr( tel2 );
|
||
|
||
if ( (tel2 = TelnoValue( vobj, VCCellularProp )) && *tel2
|
||
&& strcmp( tel1, tel2 ) != 0
|
||
&& (vcard = new_handycard( name, "-mobil", tel2 )) != NULL )
|
||
addList( &handylist, vcard );
|
||
deleteStr( tel2 );
|
||
deleteStr( tel1 );
|
||
deleteStr( name );
|
||
}
|
||
}
|
||
if ( vdel )
|
||
cleanVObject( vdel );
|
||
|
||
vobj = handylist;
|
||
while ( vobj ) {
|
||
vnext = nextVObjectInList( vobj );
|
||
addList( vlist, vobj );
|
||
vobj = vnext;
|
||
}
|
||
return OK;
|
||
}
|
||
|
||
|
||
/* -------------------- M A I N - program ----------------------------- */
|
||
static void
|
||
versinfo( void )
|
||
{
|
||
printf( "vCard/vCalendar converter %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:",
|
||
" vcaconv bin2vca binfile vcafile",
|
||
" convert IC35 binary data to vCard,vCalendar format",
|
||
" vcaconv bin2txt binfile txtfile",
|
||
" convert IC35 binary data to plain text format",
|
||
" vcaconv vca2bin vcafile binfile",
|
||
" convert vCard,vCalendar file to IC35 binary data",
|
||
" vcaconv prvca vcafile",
|
||
" pretty print vCard/vCalendar format 'vcafile'",
|
||
" vcaconv sortvca vcafile",
|
||
" sort vCard,vCalendar file to standard output",
|
||
" vcaconv imphandy vcafile",
|
||
" create vCards in HANDY category for upload to mobile phone",
|
||
" if inputfile or outputfile is absent or -, standard input",
|
||
" or standard output will be used",
|
||
"options:",
|
||
" -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' },
|
||
{ NULL, 0, NULL, 0 }
|
||
};
|
||
|
||
for ( ; ; ) {
|
||
switch ( getopt_long( argc, argv, "hV", long_opts, NULL ) ) {
|
||
default: /* invalid option */
|
||
fprintf( stderr, "use 'vcaconv --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 -1: /* end of options */
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
if ( argc < 2 ) {
|
||
error( "missing conversion\n"
|
||
"use 'vcaconv --help' for more information" );
|
||
return 1;
|
||
}
|
||
if ( ( strcmp( argv[1], "bin2vca" ) == 0
|
||
|| strcmp( argv[1], "bin2txt" ) == 0
|
||
|| strcmp( argv[1], "vca2bin" ) == 0 )
|
||
&& 2 <= argc && argc <= 4 ) {
|
||
void * rec;
|
||
|
||
argv[1][3] = '\0'; /* split input,output format */
|
||
if ( pim_openinp( argv[1]+0, argc >= 3 ? argv[2] : "-" ) != OK ) {
|
||
error( "bad input format/file: %s %s\n", argv[1]+0, argv[2] );
|
||
return 1;
|
||
}
|
||
if ( pim_openout( argv[1]+4, argc >= 4 ? argv[3] : "-" ) != OK ) {
|
||
error( "bad output format/file: %s %s\n", argv[1]+4, argv[3] );
|
||
return 1;
|
||
}
|
||
while ( (rec = pim_getrec( FILE_ANY )) != NULL )
|
||
pim_putrec( rec );
|
||
pim_close();
|
||
|
||
} else if ( strcmp( argv[1], "prvca" ) == 0
|
||
&& 2 <= argc && argc <= 3 ) {
|
||
VObject * vlist;
|
||
VObject * vdel;
|
||
|
||
if ( (vlist = vca_parse( argc >= 3 ? argv[2] : "-" )) == NULL )
|
||
return 1;
|
||
while ( vlist ) {
|
||
printVObject( stdout, vlist );
|
||
vlist = nextVObjectInList( vdel = vlist );
|
||
cleanVObject( vdel );
|
||
}
|
||
|
||
} else if ( strcmp( argv[1], "sortvca" ) == 0
|
||
&& 2 <= argc && argc <= 3 ) {
|
||
VObject * vlist;
|
||
VObject * vdel;
|
||
|
||
if ( (vlist = vca_parse( argc >= 3 ? argv[2] : "-" )) == NULL )
|
||
return 1;
|
||
vca_sort( &vlist );
|
||
while ( vlist ) {
|
||
writeVObject( stdout, vlist );
|
||
vlist = nextVObjectInList( vdel = vlist );
|
||
cleanVObject( vdel );
|
||
}
|
||
|
||
} else if ( strcmp( argv[1], "imphandy" ) == 0
|
||
&& 2 <= argc && argc <= 3 ) {
|
||
VObject * vlist;
|
||
VObject * vdel;
|
||
|
||
if ( (vlist = vca_parse( argc >= 3 ? argv[2] : "-" )) == NULL )
|
||
return 1;
|
||
vcard_to_handy( &vlist );
|
||
while ( vlist ) {
|
||
writeVObject( stdout, vlist );
|
||
vlist = nextVObjectInList( vdel = vlist );
|
||
cleanVObject( vdel );
|
||
}
|
||
|
||
} else {
|
||
error( "unknown conversion: %s\n"
|
||
"use 'vcaconv --help' for more information", argv[1] );
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|