From 66b3123dabbad8bdfc75893e0e0c4c4e63301435 Mon Sep 17 00:00:00 2001 From: eilers Date: Sat, 09 Nov 2002 14:34:52 +0000 Subject: Added VCard Backend. --- (limited to 'libopie') diff --git a/libopie/pim/ocontactaccessbackend_vcard.cpp b/libopie/pim/ocontactaccessbackend_vcard.cpp new file mode 100644 index 0000000..903c0b7 --- a/dev/null +++ b/libopie/pim/ocontactaccessbackend_vcard.cpp @@ -0,0 +1,549 @@ +/* + * VCard Backend for the OPIE-Contact Database. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program 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. + * ===================================================================== + * ToDo: + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2002/11/09 14:34:52 eilers + * Added VCard Backend. + * + */ +#include "ocontactaccessbackend_vcard.h" +#include "../../library/backend/vobject_p.h" +#include "../../library/backend/qfiledirect_p.h" + +#include + +#include + +OContactAccessBackend_VCard::OContactAccessBackend_VCard ( QString , QString filename = 0l ): + m_dirty( false ), + m_file( filename ) +{} + + +bool OContactAccessBackend_VCard::load () +{ + m_map.clear(); + m_dirty = false; + + VObject* obj = 0l; + obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); + if ( !obj ) + return false; + + while ( obj ) { + OContact con = parseVObject( obj ); + /* + * if uid is 0 assign a new one + * this at least happens on + * Nokia6210 + */ + if ( con.uid() == 0 ){ + con.setUid( 1 ); + qWarning("assigned new uid %d",con.uid() ); + } + + m_map.insert( con.uid(), con ); + + VObject *t = obj; + obj = nextVObjectInList(obj); + cleanVObject( t ); + } + + return true; + +} +bool OContactAccessBackend_VCard::reload() +{ + return load(); +} +bool OContactAccessBackend_VCard::save() +{ + if (!m_dirty ) + return true; + + QFileDirect file( m_file ); + if (!file.open(IO_WriteOnly ) ) + return false; + + VObject *obj; + obj = newVObject( VCCalProp ); + addPropValue( obj, VCVersionProp, "1.0" ); + + VObject *vo; + for(QMap::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ + vo = createVObject( *it ); + addVObjectProp( obj, vo ); + } + writeVObject( file.directHandle() , obj ); + cleanVObject( obj ); + + cleanStrTbl(); + + m_dirty = false; + return true; + + +} +void OContactAccessBackend_VCard::clear () +{ + m_map.clear(); + m_dirty = true; // ??? sure ? (se) +} + +bool OContactAccessBackend_VCard::add ( const OContact& newcontact ) +{ + m_map.insert( newcontact.uid(), newcontact ); + m_dirty = true; + return true; +} + +bool OContactAccessBackend_VCard::remove ( int uid ) +{ + m_map.remove( uid ); + m_dirty = true; + return true; +} + +bool OContactAccessBackend_VCard::replace ( const OContact &contact ) +{ + m_map.replace( contact.uid(), contact ); + m_dirty = true; + return true; +} + +OContact OContactAccessBackend_VCard::find ( int uid ) const +{ + return m_map[uid]; +} + +QArray OContactAccessBackend_VCard::allRecords() const +{ + QArray ar( m_map.count() ); + QMap::ConstIterator it; + int i = 0; + for ( it = m_map.begin(); it != m_map.end(); ++it ) { + ar[i] = it.key(); + i++; + } + return ar; +} + +// Not implemented +QArray OContactAccessBackend_VCard::queryByExample ( const OContact&, int ) +{ + QArray ar(0); + return ar; +} + +// Not implemented +QArray OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const +{ + QArray ar(0); + return ar; +} + +const uint OContactAccessBackend_VCard::querySettings() +{ + return 0; // No search possible +} + +bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const +{ + return false; // No search possible, therefore all settings invalid ;) +} + + +// *** Private stuff *** + + +OContact OContactAccessBackend_VCard::parseVObject( VObject *obj ) +{ + OContact c; + + VObjectIterator it; + initPropIterator( &it, obj ); + while( moreIteration( &it ) ) { + VObject *o = nextVObject( &it ); + QCString name = vObjectName( o ); + QCString value = vObjectStringZValue( o ); + if ( name == VCNameProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCNamePrefixesProp ) + c.setTitle( value ); + else if ( name == VCNameSuffixesProp ) + c.setSuffix( value ); + else if ( name == VCFamilyNameProp ) + c.setLastName( value ); + else if ( name == VCGivenNameProp ) + c.setFirstName( value ); + else if ( name == VCAdditionalNamesProp ) + c.setMiddleName( value ); + } + } + else if ( name == VCAdrProp ) { + bool work = TRUE; // default address is work address + QString street; + QString city; + QString region; + QString postal; + QString country; + + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCHomeProp ) + work = FALSE; + else if ( name == VCWorkProp ) + work = TRUE; + else if ( name == VCStreetAddressProp ) + street = value; + else if ( name == VCCityProp ) + city = value; + else if ( name == VCRegionProp ) + region = value; + else if ( name == VCPostalCodeProp ) + postal = value; + else if ( name == VCCountryNameProp ) + country = value; + } + if ( work ) { + c.setBusinessStreet( street ); + c.setBusinessCity( city ); + c.setBusinessCountry( country ); + c.setBusinessZip( postal ); + c.setBusinessState( region ); + } else { + c.setHomeStreet( street ); + c.setHomeCity( city ); + c.setHomeCountry( country ); + c.setHomeZip( postal ); + c.setHomeState( region ); + } + } + else if ( name == VCTelephoneProp ) { + enum { + HOME = 0x01, + WORK = 0x02, + VOICE = 0x04, + CELL = 0x08, + FAX = 0x10, + PAGER = 0x20, + UNKNOWN = 0x80 + }; + int type = 0; + + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + if ( name == VCHomeProp ) + type |= HOME; + else if ( name == VCWorkProp ) + type |= WORK; + else if ( name == VCVoiceProp ) + type |= VOICE; + else if ( name == VCCellularProp ) + type |= CELL; + else if ( name == VCFaxProp ) + type |= FAX; + else if ( name == VCPagerProp ) + type |= PAGER; + else if ( name == VCPreferredProp ) + ; + else + type |= UNKNOWN; + } + if ( (type & UNKNOWN) != UNKNOWN ) { + if ( ( type & (HOME|WORK) ) == 0 ) // default + type |= HOME; + if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default + type |= VOICE; + + if ( (type & (VOICE|HOME) ) == (VOICE|HOME) ) + c.setHomePhone( value ); + if ( ( type & (FAX|HOME) ) == (FAX|HOME) ) + c.setHomeFax( value ); + if ( ( type & (CELL|HOME) ) == (CELL|HOME) ) + c.setHomeMobile( value ); + if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) ) + c.setBusinessPhone( value ); + if ( ( type & (FAX|WORK) ) == (FAX|WORK) ) + c.setBusinessFax( value ); + if ( ( type & (CELL|WORK) ) == (CELL|WORK) ) + c.setBusinessMobile( value ); + if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) ) + c.setBusinessPager( value ); + } + } + else if ( name == VCEmailAddressProp ) { + QString email = vObjectStringZValue( o ); + bool valid = TRUE; + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + if ( name != VCInternetProp && name != VCHomeProp && + name != VCWorkProp && + name != VCPreferredProp ) + // ### preffered should map to default email + valid = FALSE; + } + if ( valid ) { + c.insertEmail( email ); + } + } + else if ( name == VCURLProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectTypeInfo( o ); + if ( name == VCHomeProp ) + c.setHomeWebpage( value ); + else if ( name == VCWorkProp ) + c.setBusinessWebpage( value ); + } + } + else if ( name == VCOrgProp ) { + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + if ( name == VCOrgNameProp ) + c.setCompany( value ); + else if ( name == VCOrgUnitProp ) + c.setDepartment( value ); + else if ( name == VCOrgUnit2Prop ) + c.setOffice( value ); + } + } + else if ( name == VCTitleProp ) { + c.setJobTitle( value ); + } + else if ( name == "X-Qtopia-Profession" ) { + c.setProfession( value ); + } + else if ( name == "X-Qtopia-Manager" ) { + c.setManager( value ); + } + else if ( name == "X-Qtopia-Assistant" ) { + c.setAssistant( value ); + } + else if ( name == "X-Qtopia-Spouse" ) { + c.setSpouse( value ); + } + else if ( name == "X-Qtopia-Gender" ) { + c.setGender( value ); + } + else if ( name == "X-Qtopia-Anniversary" ) { + c.setAnniversary( TimeConversion::fromString( value ) ); + } + else if ( name == "X-Qtopia-Nickname" ) { + c.setNickname( value ); + } + else if ( name == "X-Qtopia-Children" ) { + c.setChildren( value ); + } + else if ( name == VCBirthDateProp ) { + // Reading Birthdate regarding RFC 2425 (5.8.4) + c.setBirthday( convVCardDateToDate( value ) ); + + } + +#if 0 + else { + printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); + VObjectIterator nit; + initPropIterator( &nit, o ); + while( moreIteration( &nit ) ) { + VObject *o = nextVObject( &nit ); + QCString name = vObjectName( o ); + QString value = vObjectStringZValue( o ); + printf(" subprop: %s = %s\n", name.data(), value.latin1() ); + } + } +#endif + } + c.setFileAs(); + return c; +} + + +VObject* OContactAccessBackend_VCard::createVObject( const OContact &c ) +{ + VObject *vcard = newVObject( VCCardProp ); + safeAddPropValue( vcard, VCVersionProp, "2.1" ); + safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) ); + safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) ); + + // full name + safeAddPropValue( vcard, VCFullNameProp, c.fullName() ); + + // name properties + VObject *name = safeAddProp( vcard, VCNameProp ); + safeAddPropValue( name, VCFamilyNameProp, c.lastName() ); + safeAddPropValue( name, VCGivenNameProp, c.firstName() ); + safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() ); + safeAddPropValue( name, VCNamePrefixesProp, c.title() ); + safeAddPropValue( name, VCNameSuffixesProp, c.suffix() ); + + // home properties + VObject *home_adr= safeAddProp( vcard, VCAdrProp ); + safeAddProp( home_adr, VCHomeProp ); + safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() ); + safeAddPropValue( home_adr, VCCityProp, c.homeCity() ); + safeAddPropValue( home_adr, VCRegionProp, c.homeState() ); + safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() ); + safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() ); + + VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() ); + safeAddProp( home_phone, VCHomeProp ); + home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() ); + safeAddProp( home_phone, VCHomeProp ); + safeAddProp( home_phone, VCCellularProp ); + home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() ); + safeAddProp( home_phone, VCHomeProp ); + safeAddProp( home_phone, VCFaxProp ); + + VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() ); + safeAddProp( url, VCHomeProp ); + + // work properties + VObject *work_adr= safeAddProp( vcard, VCAdrProp ); + safeAddProp( work_adr, VCWorkProp ); + safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() ); + safeAddPropValue( work_adr, VCCityProp, c.businessCity() ); + safeAddPropValue( work_adr, VCRegionProp, c.businessState() ); + safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() ); + safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() ); + + VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() ); + safeAddProp( work_phone, VCWorkProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCCellularProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCFaxProp ); + work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() ); + safeAddProp( work_phone, VCWorkProp ); + safeAddProp( work_phone, VCPagerProp ); + + url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() ); + safeAddProp( url, VCWorkProp ); + + VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() ); + safeAddProp( title, VCWorkProp ); + + + QStringList emails = c.emailList(); + emails.prepend( c.defaultEmail() ); + for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) { + VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it ); + safeAddProp( email, VCInternetProp ); + } + + safeAddPropValue( vcard, VCNoteProp, c.notes() ); + + // Exporting Birthday regarding RFC 2425 (5.8.4) + if ( c.birthday().isValid() ){ + QString birthd_rfc2425 = QString("%1-%2-%3") + .arg( c.birthday().year() ) + .arg( c.birthday().month(), 2 ) + .arg( c.birthday().day(), 2 ); + // Now replace spaces with "0"... + int pos = 0; + while ( ( pos = birthd_rfc2425.find (' ') ) > 0 ) + birthd_rfc2425.replace( pos, 1, "0" ); + + qWarning("Exporting birthday as: %s", birthd_rfc2425.latin1()); + safeAddPropValue( vcard, VCBirthDateProp, birthd_rfc2425.latin1() ); + } + + if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) { + VObject *org = safeAddProp( vcard, VCOrgProp ); + safeAddPropValue( org, VCOrgNameProp, c.company() ); + safeAddPropValue( org, VCOrgUnitProp, c.department() ); + safeAddPropValue( org, VCOrgUnit2Prop, c.office() ); + } + + // some values we have to export as custom fields + safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() ); + safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() ); + safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() ); + + safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() ); + safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() ); + safeAddPropValue( vcard, "X-Qtopia-Anniversary", TimeConversion::toString( c.anniversary() ) ); + safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() ); + safeAddPropValue( vcard, "X-Qtopia-Children", c.children() ); + + return vcard; +} + +QDate OContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr ) +{ + int monthPos = datestr.find('-'); + int dayPos = datestr.find('-', monthPos+1 ); + int sep_ignore = 1; + if ( monthPos == -1 || dayPos == -1 ) { + qDebug("fromString didn't find - in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); + // Ok.. No "-" found, therefore we will try to read other format ( YYYYMMDD ) + if ( datestr.length() == 8 ){ + monthPos = 4; + dayPos = 6; + sep_ignore = 0; + qDebug("Try with follwing positions str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); + } else { + return QDate(); + } + } + int y = datestr.left( monthPos ).toInt(); + int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt(); + int d = datestr.mid( dayPos + sep_ignore ).toInt(); + qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, dayPos); + QDate date ( y,m,d ); + return date; +} + +VObject* OContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value ) +{ + VObject *ret = 0; + if ( o && !value.isEmpty() ) + ret = addPropValue( o, prop, value.latin1() ); + return ret; +} + +VObject* OContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop) +{ + VObject *ret = 0; + if ( o ) + ret = addProp( o, prop ); + return ret; +} diff --git a/libopie/pim/ocontactaccessbackend_vcard.h b/libopie/pim/ocontactaccessbackend_vcard.h new file mode 100644 index 0000000..c1422b0 --- a/dev/null +++ b/libopie/pim/ocontactaccessbackend_vcard.h @@ -0,0 +1,65 @@ +/* + * VCard Backend for the OPIE-Contact Database. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program 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. + * ===================================================================== + * ToDo: + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2002/11/09 14:34:52 eilers + * Added VCard Backend. + * + */ +#ifndef __OCONTACTACCESSBACKEND_VCARD_H_ +#define __OCONTACTACCESSBACKEND_VCARD_H_ + +#include + +#include "ocontactaccessbackend.h" + +class VObject; + +class OContactAccessBackend_VCard : public OContactAccessBackend { + public: + OContactAccessBackend_VCard ( QString appname, QString filename = 0l ); + + bool load (); + bool reload(); + bool save(); + void clear (); + + bool add ( const OContact& newcontact ); + bool remove ( int uid ); + bool replace ( const OContact& contact ); + + OContact find ( int uid ) const; + QArray allRecords() const; + QArray queryByExample ( const OContact &query, int settings ); + QArray matchRegexp( const QRegExp &r ) const; + + const uint querySettings(); + bool hasQuerySettings (uint querySettings) const; + +private: + OContact parseVObject( VObject* obj ); + VObject* createVObject( const OContact& c ); + QDate convVCardDateToDate( const QString& datestr ); + VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value ); + VObject *safeAddProp( VObject* o, const char* prop); + + bool m_dirty : 1; + QString m_file; + QMap m_map; +}; + +#endif -- cgit v0.9.0.2