00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <opie2/private/vobject_p.h>
00035
00036
00037 #include <opie2/ocontactaccessbackend_vcard.h>
00038 #include <opie2/odebug.h>
00039
00040 #include <qpe/timeconversion.h>
00041
00042
00043 #define protected public
00044 #include <qfile.h>
00045 #undef protected
00046
00047 namespace Opie {
00048
00049 OPimContactAccessBackend_VCard::OPimContactAccessBackend_VCard ( const QString& , const QString& filename ):
00050 m_dirty( false ),
00051 m_file( filename ),
00052 version_major( 1 ),
00053 version_minor( 0 )
00054 {
00055 load();
00056 }
00057
00058
00059 bool OPimContactAccessBackend_VCard::load ()
00060 {
00061 m_map.clear();
00062 m_dirty = false;
00063
00064 VObject* obj = 0l;
00065
00066 if ( QFile::exists(m_file) ){
00067 obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() );
00068 if ( !obj )
00069 return false;
00070 }else{
00071 odebug << "File \"" << m_file << "\" not found !" << oendl;
00072 return false;
00073 }
00074
00075 while ( obj ) {
00076 OPimContact con = parseVObject( obj );
00077
00078
00079
00080
00081
00082 if ( con.uid() == 0 ){
00083 con.setUid( 1 );
00084 owarn << "assigned new uid " << con.uid() << "" << oendl;
00085 }
00086
00087 m_map.insert( con.uid(), con );
00088
00089 VObject *t = obj;
00090 obj = nextVObjectInList(obj);
00091 cleanVObject( t );
00092 }
00093
00094 return true;
00095
00096 }
00097 bool OPimContactAccessBackend_VCard::reload()
00098 {
00099 return load();
00100 }
00101 bool OPimContactAccessBackend_VCard::save()
00102 {
00103 if (!m_dirty )
00104 return true;
00105
00106 QFile file( m_file );
00107 if (!file.open(IO_WriteOnly ) )
00108 return false;
00109
00110 VObject *obj;
00111 obj = newVObject( VCCalProp );
00112 addPropValue( obj, VCVersionProp, "1.0" );
00113
00114 VObject *vo;
00115 for(QMap<int, OPimContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){
00116 vo = createVObject( *it );
00117 writeVObject( file.fh, vo );
00118 cleanVObject( vo );
00119 }
00120 cleanStrTbl();
00121 deleteVObject( obj );
00122
00123 m_dirty = false;
00124 return true;
00125
00126
00127 }
00128 void OPimContactAccessBackend_VCard::clear ()
00129 {
00130 m_map.clear();
00131 m_dirty = true;
00132 }
00133
00134 bool OPimContactAccessBackend_VCard::add ( const OPimContact& newcontact )
00135 {
00136 m_map.insert( newcontact.uid(), newcontact );
00137 m_dirty = true;
00138 return true;
00139 }
00140
00141 bool OPimContactAccessBackend_VCard::remove ( int uid )
00142 {
00143 m_map.remove( uid );
00144 m_dirty = true;
00145 return true;
00146 }
00147
00148 bool OPimContactAccessBackend_VCard::replace ( const OPimContact &contact )
00149 {
00150 m_map.replace( contact.uid(), contact );
00151 m_dirty = true;
00152 return true;
00153 }
00154
00155 OPimContact OPimContactAccessBackend_VCard::find ( int uid ) const
00156 {
00157 return m_map[uid];
00158 }
00159
00160 UIDArray OPimContactAccessBackend_VCard::allRecords() const
00161 {
00162 UIDArray ar( m_map.count() );
00163 QMap<int, OPimContact>::ConstIterator it;
00164 int i = 0;
00165 for ( it = m_map.begin(); it != m_map.end(); ++it ) {
00166 ar[i] = it.key();
00167 i++;
00168 }
00169 return ar;
00170 }
00171
00172 bool OPimContactAccessBackend_VCard::wasChangedExternally()
00173 {
00174 return false;
00175 }
00176
00177
00178 OPimContact OPimContactAccessBackend_VCard::parseVObject( VObject *obj )
00179 {
00180 OPimContact c;
00181 VObjectIterator it;
00182 initPropIterator( &it, obj );
00183 while( moreIteration( &it ) ) {
00184 VObject *o = nextVObject( &it );
00185 QCString name = vObjectName( o );
00186 QString value = QString::fromUtf8( vObjectStringZValue( o ) );
00187 odebug << "(1)Read: " << name << " " << QString( value ).latin1() << oendl;
00188 if ( name == VCVersionProp ) {
00189
00190 odebug << "Version: " << value << oendl;
00191 QStringList version = QStringList::split( ".", value );
00192 version_major = version[0].toUInt();
00193 version_minor = version[1].toUInt();
00194 odebug << "Major: "<< version_major << " Minor: " << version_minor << oendl;
00195
00196 }
00197 else if ( name == VCNameProp ) {
00198 VObjectIterator nit;
00199 initPropIterator( &nit, o );
00200 while( moreIteration( &nit ) ) {
00201 VObject *o = nextVObject( &nit );
00202 QCString name = vObjectTypeInfo( o );
00203 QString value = QString::fromUtf8( vObjectStringZValue( o ) );
00204 odebug << "Nametype is: "<< name << " Value: " << value.latin1() << oendl;
00205 if ( name == VCNamePrefixesProp )
00206 c.setTitle( value );
00207 else if ( name == VCNameSuffixesProp )
00208 c.setSuffix( value );
00209 else if ( name == VCFamilyNameProp )
00210 c.setLastName( value );
00211 else if ( name == VCGivenNameProp )
00212 c.setFirstName( value );
00213 else if ( name == VCAdditionalNamesProp )
00214 c.setMiddleName( value );
00215 }
00216 }
00217 else if ( name == VCAdrProp ) {
00218 bool work = TRUE;
00219 QString street;
00220 QString city;
00221 QString region;
00222 QString postal;
00223 QString country;
00224
00225 VObjectIterator nit;
00226 initPropIterator( &nit, o );
00227 while( moreIteration( &nit ) ) {
00228 VObject *o = nextVObject( &nit );
00229 QCString name = vObjectTypeInfo( o );
00230 QString value = QString::fromUtf8( vObjectStringZValue( o ) );
00231 odebug << "AddressType is: "<< name << " Value: " << value.latin1() << oendl;
00232 if ( name == VCHomeProp )
00233 work = FALSE;
00234 else if ( name == VCWorkProp )
00235 work = TRUE;
00236 else if ( name == VCStreetAddressProp )
00237 street = value;
00238 else if ( name == VCCityProp )
00239 city = value;
00240 else if ( name == VCRegionProp )
00241 region = value;
00242 else if ( name == VCPostalCodeProp )
00243 postal = value;
00244 else if ( name == VCCountryNameProp )
00245 country = value;
00246 }
00247 if ( work ) {
00248 c.setBusinessStreet( street );
00249 c.setBusinessCity( city );
00250 c.setBusinessCountry( country );
00251 c.setBusinessZip( postal );
00252 c.setBusinessState( region );
00253 } else {
00254 c.setHomeStreet( street );
00255 c.setHomeCity( city );
00256 c.setHomeCountry( country );
00257 c.setHomeZip( postal );
00258 c.setHomeState( region );
00259 }
00260 }
00261 else if ( name == VCTelephoneProp ) {
00262 enum {
00263 HOME = 0x01,
00264 WORK = 0x02,
00265 VOICE = 0x04,
00266 CELL = 0x08,
00267 FAX = 0x10,
00268 PAGER = 0x20,
00269 UNKNOWN = 0x80
00270 };
00271 int type = 0;
00272
00273 VObjectIterator nit;
00274 initPropIterator( &nit, o );
00275 while( moreIteration( &nit ) ) {
00276 VObject *o = nextVObject( &nit );
00277 QCString name = vObjectTypeInfo( o );
00278 odebug << "Telephonetype is: "<< name << " Value: " << value.latin1() << oendl;
00279 if ( name == VCHomeProp )
00280 type |= HOME;
00281 else if ( name == VCWorkProp )
00282 type |= WORK;
00283 else if ( name == VCVoiceProp )
00284 type |= VOICE;
00285 else if ( name == VCCellularProp )
00286 type |= CELL;
00287 else if ( name == VCFaxProp )
00288 type |= FAX;
00289 else if ( name == VCPagerProp )
00290 type |= PAGER;
00291 else if ( name == VCPreferredProp )
00292 ;
00293 else if ( name.left( 2 ) == "X-" || name.left( 2 ) == "x-" )
00294 ;
00295 else
00296 type |= UNKNOWN;
00297 }
00298 if ( (type & UNKNOWN) != UNKNOWN ) {
00299 if ( ( type & (HOME|WORK) ) == 0 )
00300 type |= HOME;
00301 if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 )
00302 type |= VOICE;
00303
00304 odebug << "value %s %d" << value.data() << type << oendl;
00305
00306 if ( (type & (VOICE|HOME) ) == (VOICE|HOME) && (type & (CELL|HOME) ) != (CELL|HOME) )
00307 c.setHomePhone( value );
00308 if ( ( type & (FAX|HOME) ) == (FAX|HOME) )
00309 c.setHomeFax( value );
00310 if ( ( type & (CELL|HOME) ) == (CELL|HOME) )
00311 c.setHomeMobile( value );
00312 if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) && (type & (CELL|WORK) ) != (CELL|WORK) )
00313 c.setBusinessPhone( value );
00314 if ( ( type & (FAX|WORK) ) == (FAX|WORK) )
00315 c.setBusinessFax( value );
00316 if ( ( type & (CELL|WORK) ) == (CELL|WORK) )
00317 c.setBusinessMobile( value );
00318 if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) )
00319 c.setBusinessPager( value );
00320 }
00321 }
00322 else if ( name == VCEmailAddressProp ) {
00323 QString email = QString::fromUtf8( vObjectStringZValue( o ) );
00324 bool valid = TRUE;
00325 VObjectIterator nit;
00326 initPropIterator( &nit, o );
00327 while( moreIteration( &nit ) ) {
00328 VObject *o = nextVObject( &nit );
00329 QCString name = vObjectTypeInfo( o );
00330 odebug << "Emailtype is: "<< name << " Value: " << value.latin1() << oendl;
00331 if ( name != VCInternetProp && name != VCHomeProp &&
00332 name != VCWorkProp &&
00333 name != VCPreferredProp &&
00334 name.left( 2 ) != "X-" && name.left( 2 ) != "x-" ){
00335
00336 valid = FALSE;
00337 odebug << "Email was detected as invalid!" << oendl;
00338 }
00339 }
00340 if ( valid ) {
00341 c.insertEmail( email );
00342 }
00343 }
00344 else if ( name == VCURLProp ) {
00345 VObjectIterator nit;
00346 initPropIterator( &nit, o );
00347 while( moreIteration( &nit ) ) {
00348 VObject *o = nextVObject( &nit );
00349 QCString name = vObjectTypeInfo( o );
00350 if ( name == VCHomeProp )
00351 c.setHomeWebpage( value );
00352 else if ( name == VCWorkProp )
00353 c.setBusinessWebpage( value );
00354 }
00355 }
00356 else if ( name == VCOrgProp ) {
00357 VObjectIterator nit;
00358 initPropIterator( &nit, o );
00359 while( moreIteration( &nit ) ) {
00360 VObject *o = nextVObject( &nit );
00361 QCString name = vObjectName( o );
00362 QString value = QString::fromUtf8( vObjectStringZValue( o ) );
00363 if ( name == VCOrgNameProp )
00364 c.setCompany( value );
00365 else if ( name == VCOrgUnitProp )
00366 c.setDepartment( value );
00367 else if ( name == VCOrgUnit2Prop )
00368 c.setOffice( value );
00369 }
00370 }
00371 else if ( name == VCTitleProp ) {
00372 c.setJobTitle( value );
00373 }
00374 else if ( name == "X-Qtopia-Profession" ) {
00375 c.setProfession( value );
00376 }
00377 else if ( name == "X-Qtopia-Manager" ) {
00378 c.setManager( value );
00379 }
00380 else if ( name == "X-Qtopia-Assistant" ) {
00381 c.setAssistant( value );
00382 }
00383 else if ( name == "X-Qtopia-Spouse" ) {
00384 c.setSpouse( value );
00385 }
00386 else if ( name == "X-Qtopia-Gender" ) {
00387 c.setGender( value );
00388 }
00389 else if ( name == "X-Qtopia-Anniversary" ) {
00390 c.setAnniversary( convVCardDateToDate( value ) );
00391 }
00392 else if ( name == "X-Qtopia-Nickname" ) {
00393 c.setNickname( value );
00394 }
00395 else if ( name == "X-Qtopia-Children" ) {
00396 c.setChildren( value );
00397 }
00398 else if ( name == VCBirthDateProp ) {
00399
00400 c.setBirthday( convVCardDateToDate( value ) );
00401
00402 }
00403 else if ( name == VCCommentProp ) {
00404 c.setNotes( value );
00405 }
00406 #if 0
00407 else {
00408 printf("Name: %s, value=%s\n", name.data(), QString::fromUtf8( vObjectStringZValue( o ) ) );
00409 VObjectIterator nit;
00410 initPropIterator( &nit, o );
00411 while( moreIteration( &nit ) ) {
00412 VObject *o = nextVObject( &nit );
00413 QCString name = vObjectName( o );
00414 QString value = QString::fromUtf8( vObjectStringZValue( o ) );
00415 printf(" subprop: %s = %s\n", name.data(), value.latin1() );
00416 }
00417 }
00418 else {
00419 printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) );
00420 VObjectIterator nit;
00421 initPropIterator( &nit, o );
00422 while( moreIteration( &nit ) ) {
00423 VObject *o = nextVObject( &nit );
00424 QCString name = vObjectName( o );
00425 QString value = vObjectStringZValue( o );
00426 printf(" subprop: %s = %s\n", name.data(), value.latin1() );
00427 }
00428 }
00429 #endif
00430 }
00431 c.setFileAs();
00432 return c;
00433 }
00434
00435
00436 VObject* OPimContactAccessBackend_VCard::createVObject( const OPimContact &c )
00437 {
00438 VObject *vcard = newVObject( VCCardProp );
00439 safeAddPropValue( vcard, VCVersionProp, "2.1" );
00440 safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) );
00441 safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) );
00442
00443
00444 safeAddPropValue( vcard, VCFullNameProp, c.fullName() );
00445
00446
00447 VObject *name = safeAddProp( vcard, VCNameProp );
00448 safeAddPropValue( name, VCFamilyNameProp, c.lastName() );
00449 safeAddPropValue( name, VCGivenNameProp, c.firstName() );
00450 safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() );
00451 safeAddPropValue( name, VCNamePrefixesProp, c.title() );
00452 safeAddPropValue( name, VCNameSuffixesProp, c.suffix() );
00453
00454
00455 if ( !( c.homeStreet().isEmpty()
00456 && c.homeCity().isEmpty()
00457 && c.homeState().isEmpty()
00458 && c.homeZip().isEmpty()
00459 && c.homeCountry().isEmpty() ) ){
00460 VObject *home_adr= safeAddProp( vcard, VCAdrProp );
00461 safeAddProp( home_adr, VCHomeProp );
00462 safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() );
00463 safeAddPropValue( home_adr, VCCityProp, c.homeCity() );
00464 safeAddPropValue( home_adr, VCRegionProp, c.homeState() );
00465 safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() );
00466 safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() );
00467 }
00468
00469 VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() );
00470 safeAddProp( home_phone, VCHomeProp );
00471 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() );
00472 safeAddProp( home_phone, VCHomeProp );
00473 safeAddProp( home_phone, VCCellularProp );
00474 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() );
00475 safeAddProp( home_phone, VCHomeProp );
00476 safeAddProp( home_phone, VCFaxProp );
00477
00478 VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() );
00479 safeAddProp( url, VCHomeProp );
00480
00481
00482 if ( !( c.businessStreet().isEmpty()
00483 && c.businessCity().isEmpty()
00484 && c.businessState().isEmpty()
00485 && c.businessZip().isEmpty()
00486 && c.businessCountry().isEmpty() ) ){
00487 VObject *work_adr= safeAddProp( vcard, VCAdrProp );
00488 safeAddProp( work_adr, VCWorkProp );
00489 safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() );
00490 safeAddPropValue( work_adr, VCCityProp, c.businessCity() );
00491 safeAddPropValue( work_adr, VCRegionProp, c.businessState() );
00492 safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() );
00493 safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() );
00494 }
00495
00496 VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() );
00497 safeAddProp( work_phone, VCWorkProp );
00498 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() );
00499 safeAddProp( work_phone, VCWorkProp );
00500 safeAddProp( work_phone, VCCellularProp );
00501 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() );
00502 safeAddProp( work_phone, VCWorkProp );
00503 safeAddProp( work_phone, VCFaxProp );
00504 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() );
00505 safeAddProp( work_phone, VCWorkProp );
00506 safeAddProp( work_phone, VCPagerProp );
00507
00508 url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() );
00509 safeAddProp( url, VCWorkProp );
00510
00511 VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() );
00512 safeAddProp( title, VCWorkProp );
00513
00514
00515 QStringList emails = c.emailList();
00516
00517 for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) {
00518 VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it );
00519 safeAddProp( email, VCInternetProp );
00520 }
00521
00522 safeAddPropValue( vcard, VCNoteProp, c.notes() );
00523
00524
00525 if ( c.birthday().isValid() ){
00526 safeAddPropValue( vcard, VCBirthDateProp, convDateToVCardDate( c.birthday() ) );
00527 }
00528
00529 if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) {
00530 VObject *org = safeAddProp( vcard, VCOrgProp );
00531 safeAddPropValue( org, VCOrgNameProp, c.company() );
00532 safeAddPropValue( org, VCOrgUnitProp, c.department() );
00533 safeAddPropValue( org, VCOrgUnit2Prop, c.office() );
00534 }
00535
00536
00537 safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() );
00538 safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() );
00539 safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() );
00540
00541 safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() );
00542 safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() );
00543 if ( c.anniversary().isValid() ){
00544 safeAddPropValue( vcard, "X-Qtopia-Anniversary", convDateToVCardDate( c.anniversary() ) );
00545 }
00546 safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() );
00547 safeAddPropValue( vcard, "X-Qtopia-Children", c.children() );
00548
00549 return vcard;
00550 }
00551
00552 QString OPimContactAccessBackend_VCard::convDateToVCardDate( const QDate& d ) const
00553 {
00554 QString str_rfc2425 = QString("%1-%2-%3")
00555 .arg( d.year() )
00556 .arg( d.month(), 2 )
00557 .arg( d.day(), 2 );
00558
00559 int pos = 0;
00560 while ( ( pos = str_rfc2425.find (' ') ) > 0 )
00561 str_rfc2425.replace( pos, 1, "0" );
00562
00563 return str_rfc2425;
00564 }
00565
00566 QDate OPimContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr )
00567 {
00568 int monthPos = datestr.find('-');
00569 int dayPos = datestr.find('-', monthPos+1 );
00570 int sep_ignore = 1;
00571 if ( monthPos == -1 || dayPos == -1 ) {
00572 odebug << "fromString didn't find - in str = " << datestr << "; mpos = " << monthPos << " ypos = " << dayPos << "" << oendl;
00573
00574 if ( datestr.length() == 8 ){
00575 monthPos = 4;
00576 dayPos = 6;
00577 sep_ignore = 0;
00578 odebug << "Try with follwing positions str = " << datestr << "; mpos = " << monthPos << " ypos = " << dayPos << "" << oendl;
00579 } else {
00580 return QDate();
00581 }
00582 }
00583 int y = datestr.left( monthPos ).toInt();
00584 int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt();
00585 int d = datestr.mid( dayPos + sep_ignore ).toInt();
00586 odebug << "TimeConversion::fromString ymd = " << datestr << " => " << y << " " << m << " " << d << "; mpos = " << monthPos << " ypos = " << dayPos << "" << oendl;
00587 QDate date ( y,m,d );
00588 return date;
00589 }
00590
00591 VObject* OPimContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value )
00592 {
00593 VObject *ret = 0;
00594 if ( o && !value.isEmpty() )
00595 ret = addPropValue( o, prop, value.utf8() );
00596 return ret;
00597 }
00598
00599 VObject* OPimContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop)
00600 {
00601 VObject *ret = 0;
00602 if ( o )
00603 ret = addProp( o, prop );
00604 return ret;
00605 }
00606
00607
00608
00609 }