vcardtool.cpp
00001 /* 00002 This file is part of libkabc. 00003 Copyright (c) 2003 Tobias Koenig <tokoe@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include <tqbuffer.h> 00022 #include <tqdatastream.h> 00023 #include <tqregexp.h> 00024 #include <tqstring.h> 00025 00026 #include "agent.h" 00027 #include "key.h" 00028 #include "picture.h" 00029 #include "secrecy.h" 00030 #include "sound.h" 00031 00032 #include "vcardtool.h" 00033 00034 using namespace KABC; 00035 00036 static bool needsEncoding( const TQString &value ) 00037 { 00038 uint length = value.length(); 00039 for ( uint i = 0; i < length; ++i ) { 00040 char c = value.at( i ).latin1(); 00041 if ( (c < 33 || c > 126) && c != ' ' && c != '=' ) 00042 return true; 00043 } 00044 00045 return false; 00046 } 00047 00048 VCardTool::VCardTool() 00049 { 00050 mAddressTypeMap.insert( "dom", Address::Dom ); 00051 mAddressTypeMap.insert( "intl", Address::Intl ); 00052 mAddressTypeMap.insert( "postal", Address::Postal ); 00053 mAddressTypeMap.insert( "parcel", Address::Parcel ); 00054 mAddressTypeMap.insert( "home", Address::Home ); 00055 mAddressTypeMap.insert( "work", Address::Work ); 00056 mAddressTypeMap.insert( "pref", Address::Pref ); 00057 00058 mPhoneTypeMap.insert( "HOME", PhoneNumber::Home ); 00059 mPhoneTypeMap.insert( "WORK", PhoneNumber::Work ); 00060 mPhoneTypeMap.insert( "MSG", PhoneNumber::Msg ); 00061 mPhoneTypeMap.insert( "PREF", PhoneNumber::Pref ); 00062 mPhoneTypeMap.insert( "VOICE", PhoneNumber::Voice ); 00063 mPhoneTypeMap.insert( "FAX", PhoneNumber::Fax ); 00064 mPhoneTypeMap.insert( "CELL", PhoneNumber::Cell ); 00065 mPhoneTypeMap.insert( "VIDEO", PhoneNumber::Video ); 00066 mPhoneTypeMap.insert( "BBS", PhoneNumber::Bbs ); 00067 mPhoneTypeMap.insert( "MODEM", PhoneNumber::Modem ); 00068 mPhoneTypeMap.insert( "CAR", PhoneNumber::Car ); 00069 mPhoneTypeMap.insert( "ISDN", PhoneNumber::Isdn ); 00070 mPhoneTypeMap.insert( "PCS", PhoneNumber::Pcs ); 00071 mPhoneTypeMap.insert( "PAGER", PhoneNumber::Pager ); 00072 } 00073 00074 VCardTool::~VCardTool() 00075 { 00076 } 00077 00078 // TODO: make list a const& 00079 TQString VCardTool::createVCards( Addressee::List list, VCard::Version version ) 00080 { 00081 VCard::List vCardList; 00082 00083 Addressee::List::ConstIterator addrIt; 00084 Addressee::List::ConstIterator listEnd( list.constEnd() ); 00085 for ( addrIt = list.constBegin(); addrIt != listEnd; ++addrIt ) { 00086 VCard card; 00087 TQStringList::ConstIterator strIt; 00088 00089 // ADR + LABEL 00090 const Address::List addresses = (*addrIt).addresses(); 00091 for ( Address::List::ConstIterator it = addresses.begin(); it != addresses.end(); ++it ) { 00092 TQStringList address; 00093 00094 bool isEmpty = ( (*it).postOfficeBox().isEmpty() && 00095 (*it).extended().isEmpty() && 00096 (*it).street().isEmpty() && 00097 (*it).locality().isEmpty() && 00098 (*it).region().isEmpty() && 00099 (*it).postalCode().isEmpty() && 00100 (*it).country().isEmpty() ); 00101 00102 address.append( (*it).postOfficeBox().replace( ';', "\\;" ) ); 00103 address.append( (*it).extended().replace( ';', "\\;" ) ); 00104 address.append( (*it).street().replace( ';', "\\;" ) ); 00105 address.append( (*it).locality().replace( ';', "\\;" ) ); 00106 address.append( (*it).region().replace( ';', "\\;" ) ); 00107 address.append( (*it).postalCode().replace( ';', "\\;" ) ); 00108 address.append( (*it).country().replace( ';', "\\;" ) ); 00109 00110 VCardLine adrLine( "ADR", address.join( ";" ) ); 00111 if ( version == VCard::v2_1 && needsEncoding( address.join( ";" ) ) ) { 00112 adrLine.addParameter( "charset", "UTF-8" ); 00113 adrLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00114 } 00115 00116 VCardLine labelLine( "LABEL", (*it).label() ); 00117 if ( version == VCard::v2_1 && needsEncoding( (*it).label() ) ) { 00118 labelLine.addParameter( "charset", "UTF-8" ); 00119 labelLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00120 } 00121 00122 bool hasLabel = !(*it).label().isEmpty(); 00123 TQMap<TQString, int>::ConstIterator typeIt; 00124 for ( typeIt = mAddressTypeMap.constBegin(); typeIt != mAddressTypeMap.constEnd(); ++typeIt ) { 00125 if ( typeIt.data() & (*it).type() ) { 00126 adrLine.addParameter( "TYPE", typeIt.key() ); 00127 if ( hasLabel ) 00128 labelLine.addParameter( "TYPE", typeIt.key() ); 00129 } 00130 } 00131 00132 if ( !isEmpty ) 00133 card.addLine( adrLine ); 00134 if ( hasLabel ) 00135 card.addLine( labelLine ); 00136 } 00137 00138 // AGENT 00139 card.addLine( createAgent( version, (*addrIt).agent() ) ); 00140 00141 // BDAY 00142 card.addLine( VCardLine( "BDAY", createDateTime( TQT_TQDATETIME_OBJECT((*addrIt).birthday()) ) ) ); 00143 00144 // CATEGORIES 00145 if ( version == VCard::v3_0 ) { 00146 TQStringList categories = (*addrIt).categories(); 00147 TQStringList::Iterator catIt; 00148 for ( catIt = categories.begin(); catIt != categories.end(); ++catIt ) 00149 (*catIt).replace( ',', "\\," ); 00150 00151 VCardLine catLine( "CATEGORIES", categories.join( "," ) ); 00152 if ( version == VCard::v2_1 && needsEncoding( categories.join( "," ) ) ) { 00153 catLine.addParameter( "charset", "UTF-8" ); 00154 catLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00155 } 00156 00157 card.addLine( catLine ); 00158 } 00159 00160 // CLASS 00161 if ( version == VCard::v3_0 ) { 00162 card.addLine( createSecrecy( (*addrIt).secrecy() ) ); 00163 } 00164 00165 // EMAIL 00166 const TQStringList emails = (*addrIt).emails(); 00167 bool pref = true; 00168 for ( strIt = emails.begin(); strIt != emails.end(); ++strIt ) { 00169 VCardLine line( "EMAIL", *strIt ); 00170 if ( pref == true && emails.count() > 1 ) { 00171 line.addParameter( "TYPE", "PREF" ); 00172 pref = false; 00173 } 00174 card.addLine( line ); 00175 } 00176 00177 // FN 00178 VCardLine fnLine( "FN", TQString((*addrIt).formattedName()) ); 00179 if ( version == VCard::v2_1 && needsEncoding( (*addrIt).formattedName() ) ) { 00180 fnLine.addParameter( "charset", "UTF-8" ); 00181 fnLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00182 } 00183 card.addLine( fnLine ); 00184 00185 // GEO 00186 Geo geo = (*addrIt).geo(); 00187 if ( geo.isValid() ) { 00188 TQString str; 00189 str.sprintf( "%.6f;%.6f", geo.latitude(), geo.longitude() ); 00190 card.addLine( VCardLine( "GEO", str ) ); 00191 } 00192 00193 // KEY 00194 const Key::List keys = (*addrIt).keys(); 00195 Key::List::ConstIterator keyIt; 00196 for ( keyIt = keys.begin(); keyIt != keys.end(); ++keyIt ) 00197 card.addLine( createKey( *keyIt ) ); 00198 00199 // LOGO 00200 card.addLine( createPicture( "LOGO", (*addrIt).logo() ) ); 00201 00202 // MAILER 00203 VCardLine mailerLine( "MAILER", TQString((*addrIt).mailer()) ); 00204 if ( version == VCard::v2_1 && needsEncoding( (*addrIt).mailer() ) ) { 00205 mailerLine.addParameter( "charset", "UTF-8" ); 00206 mailerLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00207 } 00208 card.addLine( mailerLine ); 00209 00210 // N 00211 TQStringList name; 00212 name.append( (*addrIt).familyName().replace( ';', "\\;" ) ); 00213 name.append( (*addrIt).givenName().replace( ';', "\\;" ) ); 00214 name.append( (*addrIt).additionalName().replace( ';', "\\;" ) ); 00215 name.append( (*addrIt).prefix().replace( ';', "\\;" ) ); 00216 name.append( (*addrIt).suffix().replace( ';', "\\;" ) ); 00217 00218 VCardLine nLine( "N", name.join( ";" ) ); 00219 if ( version == VCard::v2_1 && needsEncoding( name.join( ";" ) ) ) { 00220 nLine.addParameter( "charset", "UTF-8" ); 00221 nLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00222 } 00223 card.addLine( nLine ); 00224 00225 // NAME 00226 VCardLine nameLine( "NAME", TQString((*addrIt).name()) ); 00227 if ( version == VCard::v2_1 && needsEncoding( (*addrIt).name() ) ) { 00228 nameLine.addParameter( "charset", "UTF-8" ); 00229 nameLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00230 } 00231 card.addLine( nameLine ); 00232 00233 // NICKNAME 00234 if ( version == VCard::v3_0 ) 00235 card.addLine( VCardLine( "NICKNAME", TQString((*addrIt).nickName()) ) ); 00236 00237 // NOTE 00238 VCardLine noteLine( "NOTE", TQString((*addrIt).note()) ); 00239 if ( version == VCard::v2_1 && needsEncoding( (*addrIt).note() ) ) { 00240 noteLine.addParameter( "charset", "UTF-8" ); 00241 noteLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00242 } 00243 card.addLine( noteLine ); 00244 00245 // ORG 00246 TQStringList organization; 00247 organization.append( ( *addrIt ).organization().replace( ';', "\\;" ) ); 00248 if ( !( *addrIt ).department().isEmpty() ) 00249 organization.append( ( *addrIt ).department().replace( ';', "\\;" ) ); 00250 VCardLine orgLine( "ORG", organization.join( ";" ) ); 00251 if ( version == VCard::v2_1 && needsEncoding( organization.join( ";" ) ) ) { 00252 orgLine.addParameter( "charset", "UTF-8" ); 00253 orgLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00254 } 00255 card.addLine( orgLine ); 00256 00257 // PHOTO 00258 card.addLine( createPicture( "PHOTO", (*addrIt).photo() ) ); 00259 00260 // PROID 00261 if ( version == VCard::v3_0 ) 00262 card.addLine( VCardLine( "PRODID", TQString((*addrIt).productId()) ) ); 00263 00264 // REV 00265 card.addLine( VCardLine( "REV", createDateTime( TQT_TQDATETIME_OBJECT((*addrIt).revision()) ) ) ); 00266 00267 // ROLE 00268 VCardLine roleLine( "ROLE", TQString((*addrIt).role()) ); 00269 if ( version == VCard::v2_1 && needsEncoding( (*addrIt).role() ) ) { 00270 roleLine.addParameter( "charset", "UTF-8" ); 00271 roleLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00272 } 00273 card.addLine( roleLine ); 00274 00275 // SORT-STRING 00276 if ( version == VCard::v3_0 ) 00277 card.addLine( VCardLine( "SORT-STRING", TQString((*addrIt).sortString()) ) ); 00278 00279 // SOUND 00280 card.addLine( createSound( (*addrIt).sound() ) ); 00281 00282 // TEL 00283 const PhoneNumber::List phoneNumbers = (*addrIt).phoneNumbers(); 00284 PhoneNumber::List::ConstIterator phoneIt; 00285 for ( phoneIt = phoneNumbers.begin(); phoneIt != phoneNumbers.end(); ++phoneIt ) { 00286 VCardLine line( "TEL", (*phoneIt).number() ); 00287 00288 TQMap<TQString, int>::ConstIterator typeIt; 00289 for ( typeIt = mPhoneTypeMap.constBegin(); typeIt != mPhoneTypeMap.constEnd(); ++typeIt ) { 00290 if ( typeIt.data() & (*phoneIt).type() ) 00291 line.addParameter( "TYPE", typeIt.key() ); 00292 } 00293 00294 card.addLine( line ); 00295 } 00296 00297 // TITLE 00298 VCardLine titleLine( "TITLE", TQString((*addrIt).title()) ); 00299 if ( version == VCard::v2_1 && needsEncoding( (*addrIt).title() ) ) { 00300 titleLine.addParameter( "charset", "UTF-8" ); 00301 titleLine.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00302 } 00303 card.addLine( titleLine ); 00304 00305 // TZ 00306 TimeZone timeZone = (*addrIt).timeZone(); 00307 if ( timeZone.isValid() ) { 00308 TQString str; 00309 00310 int neg = 1; 00311 if ( timeZone.offset() < 0 ) 00312 neg = -1; 00313 00314 str.sprintf( "%c%02d:%02d", ( timeZone.offset() >= 0 ? '+' : '-' ), 00315 ( timeZone.offset() / 60 ) * neg, 00316 ( timeZone.offset() % 60 ) * neg ); 00317 00318 card.addLine( VCardLine( "TZ", str ) ); 00319 } 00320 00321 // UID 00322 card.addLine( VCardLine( "UID", (*addrIt).uid() ) ); 00323 00324 // UID 00325 card.addLine( VCardLine( "URI", (*addrIt).uri() ) ); 00326 00327 // URL 00328 card.addLine( VCardLine( "URL", (*addrIt).url().url() ) ); 00329 00330 // VERSION 00331 if ( version == VCard::v2_1 ) 00332 card.addLine( VCardLine( "VERSION", "2.1" ) ); 00333 if ( version == VCard::v3_0 ) 00334 card.addLine( VCardLine( "VERSION", "3.0" ) ); 00335 00336 // X- 00337 const TQStringList customs = (*addrIt).customs(); 00338 for ( strIt = customs.begin(); strIt != customs.end(); ++strIt ) { 00339 TQString identifier = "X-" + (*strIt).left( (*strIt).find( ":" ) ); 00340 TQString value = (*strIt).mid( (*strIt).find( ":" ) + 1 ); 00341 if ( value.isEmpty() ) 00342 continue; 00343 00344 VCardLine line( identifier, value ); 00345 if ( version == VCard::v2_1 && needsEncoding( value ) ) { 00346 line.addParameter( "charset", "UTF-8" ); 00347 line.addParameter( "encoding", "QUOTED-PRINTABLE" ); 00348 } 00349 card.addLine( line ); 00350 } 00351 00352 vCardList.append( card ); 00353 } 00354 00355 return VCardParser::createVCards( vCardList ); 00356 } 00357 00358 Addressee::List VCardTool::parseVCards( const TQString& vcard ) 00359 { 00360 static const TQChar semicolonSep( ';' ); 00361 static const TQChar commaSep( ',' ); 00362 TQString identifier; 00363 00364 Addressee::List addrList; 00365 const VCard::List vCardList = VCardParser::parseVCards( vcard ); 00366 00367 VCard::List::ConstIterator cardIt; 00368 VCard::List::ConstIterator listEnd( vCardList.end() ); 00369 for ( cardIt = vCardList.begin(); cardIt != listEnd; ++cardIt ) { 00370 Addressee addr; 00371 00372 const TQStringList idents = (*cardIt).identifiers(); 00373 TQStringList::ConstIterator identIt; 00374 TQStringList::ConstIterator identEnd( idents.end() ); 00375 for ( identIt = idents.begin(); identIt != identEnd; ++identIt ) { 00376 const VCardLine::List lines = (*cardIt).lines( (*identIt) ); 00377 VCardLine::List::ConstIterator lineIt; 00378 00379 // iterate over the lines 00380 for ( lineIt = lines.begin(); lineIt != lines.end(); ++lineIt ) { 00381 identifier = (*lineIt).identifier().lower(); 00382 // ADR 00383 if ( identifier == "adr" ) { 00384 Address address; 00385 const TQStringList addrParts = splitString( semicolonSep, (*lineIt).value().asString() ); 00386 if ( addrParts.count() > 0 ) 00387 address.setPostOfficeBox( addrParts[ 0 ] ); 00388 if ( addrParts.count() > 1 ) 00389 address.setExtended( addrParts[ 1 ] ); 00390 if ( addrParts.count() > 2 ) 00391 address.setStreet( addrParts[ 2 ] ); 00392 if ( addrParts.count() > 3 ) 00393 address.setLocality( addrParts[ 3 ] ); 00394 if ( addrParts.count() > 4 ) 00395 address.setRegion( addrParts[ 4 ] ); 00396 if ( addrParts.count() > 5 ) 00397 address.setPostalCode( addrParts[ 5 ] ); 00398 if ( addrParts.count() > 6 ) 00399 address.setCountry( addrParts[ 6 ] ); 00400 00401 int type = 0; 00402 00403 const TQStringList types = (*lineIt).parameters( "type" ); 00404 for ( TQStringList::ConstIterator it = types.begin(); it != types.end(); ++it ) 00405 type += mAddressTypeMap[ (*it).lower() ]; 00406 00407 address.setType( type ); 00408 addr.insertAddress( address ); 00409 } 00410 00411 // AGENT 00412 else if ( identifier == "agent" ) 00413 addr.setAgent( parseAgent( *lineIt ) ); 00414 00415 // BDAY 00416 else if ( identifier == "bday" ) { 00417 TQString s((*lineIt).value().asString()); 00418 if ( s.length() > 0 ) 00419 addr.setBirthday( parseDateTime( s ) ); 00420 } 00421 00422 // CATEGORIES 00423 else if ( identifier == "categories" ) { 00424 const TQStringList categories = splitString( commaSep, (*lineIt).value().asString() ); 00425 addr.setCategories( categories ); 00426 } 00427 00428 // CLASS 00429 else if ( identifier == "class" ) 00430 addr.setSecrecy( parseSecrecy( *lineIt ) ); 00431 00432 // EMAIL 00433 else if ( identifier == "email" ) { 00434 const TQStringList types = (*lineIt).parameters( "type" ); 00435 addr.insertEmail( (*lineIt).value().asString(), types.findIndex( "PREF" ) != -1 ); 00436 } 00437 00438 // FN 00439 else if ( identifier == "fn" ) 00440 addr.setFormattedName( (*lineIt).value().asString() ); 00441 00442 // GEO 00443 else if ( identifier == "geo" ) { 00444 Geo geo; 00445 00446 const TQStringList geoParts = TQStringList::split( ';', (*lineIt).value().asString(), true ); 00447 geo.setLatitude( geoParts[ 0 ].toFloat() ); 00448 geo.setLongitude( geoParts[ 1 ].toFloat() ); 00449 00450 addr.setGeo( geo ); 00451 } 00452 00453 // KEY 00454 else if ( identifier == "key" ) 00455 addr.insertKey( parseKey( *lineIt ) ); 00456 00457 // LABEL 00458 else if ( identifier == "label" ) { 00459 int type = 0; 00460 00461 const TQStringList types = (*lineIt).parameters( "type" ); 00462 for ( TQStringList::ConstIterator it = types.begin(); it != types.end(); ++it ) 00463 type += mAddressTypeMap[ (*it).lower() ]; 00464 00465 bool available = false; 00466 KABC::Address::List addressList = addr.addresses(); 00467 KABC::Address::List::Iterator it; 00468 for ( it = addressList.begin(); it != addressList.end(); ++it ) { 00469 if ( (*it).type() == type ) { 00470 (*it).setLabel( (*lineIt).value().asString() ); 00471 addr.insertAddress( *it ); 00472 available = true; 00473 break; 00474 } 00475 } 00476 00477 if ( !available ) { // a standalone LABEL tag 00478 KABC::Address address( type ); 00479 address.setLabel( (*lineIt).value().asString() ); 00480 addr.insertAddress( address ); 00481 } 00482 } 00483 00484 // LOGO 00485 else if ( identifier == "logo" ) 00486 addr.setLogo( parsePicture( *lineIt ) ); 00487 00488 // MAILER 00489 else if ( identifier == "mailer" ) 00490 addr.setMailer( (*lineIt).value().asString() ); 00491 00492 // N 00493 else if ( identifier == "n" ) { 00494 const TQStringList nameParts = splitString( semicolonSep, (*lineIt).value().asString() ); 00495 if ( nameParts.count() > 0 ) 00496 addr.setFamilyName( nameParts[ 0 ] ); 00497 if ( nameParts.count() > 1 ) 00498 addr.setGivenName( nameParts[ 1 ] ); 00499 if ( nameParts.count() > 2 ) 00500 addr.setAdditionalName( nameParts[ 2 ] ); 00501 if ( nameParts.count() > 3 ) 00502 addr.setPrefix( nameParts[ 3 ] ); 00503 if ( nameParts.count() > 4 ) 00504 addr.setSuffix( nameParts[ 4 ] ); 00505 } 00506 00507 // NAME 00508 else if ( identifier == "name" ) 00509 addr.setName( (*lineIt).value().asString() ); 00510 00511 // NICKNAME 00512 else if ( identifier == "nickname" ) 00513 addr.setNickName( (*lineIt).value().asString() ); 00514 00515 // NOTE 00516 else if ( identifier == "note" ) 00517 addr.setNote( (*lineIt).value().asString() ); 00518 00519 // ORGANIZATION 00520 else if ( identifier == "org" ) { 00521 const TQStringList orgParts = splitString( semicolonSep, (*lineIt).value().asString() ); 00522 if ( orgParts.count() > 0 ) 00523 addr.setOrganization( orgParts[ 0 ] ); 00524 if ( orgParts.count() > 1 ) 00525 addr.setDepartment( orgParts[ 1 ] ); 00526 } 00527 00528 // PHOTO 00529 else if ( identifier == "photo" ) 00530 addr.setPhoto( parsePicture( *lineIt ) ); 00531 00532 // PROID 00533 else if ( identifier == "prodid" ) 00534 addr.setProductId( (*lineIt).value().asString() ); 00535 00536 // REV 00537 else if ( identifier == "rev" ) 00538 addr.setRevision( parseDateTime( (*lineIt).value().asString() ) ); 00539 00540 // ROLE 00541 else if ( identifier == "role" ) 00542 addr.setRole( (*lineIt).value().asString() ); 00543 00544 // SORT-STRING 00545 else if ( identifier == "sort-string" ) 00546 addr.setSortString( (*lineIt).value().asString() ); 00547 00548 // SOUND 00549 else if ( identifier == "sound" ) 00550 addr.setSound( parseSound( *lineIt ) ); 00551 00552 // TEL 00553 else if ( identifier == "tel" ) { 00554 PhoneNumber phone; 00555 phone.setNumber( (*lineIt).value().asString() ); 00556 00557 int type = 0; 00558 00559 const TQStringList types = (*lineIt).parameters( "type" ); 00560 for ( TQStringList::ConstIterator it = types.begin(); it != types.end(); ++it ) 00561 type += mPhoneTypeMap[(*it).upper()]; 00562 00563 phone.setType( type ); 00564 00565 addr.insertPhoneNumber( phone ); 00566 } 00567 00568 // TITLE 00569 else if ( identifier == "title" ) 00570 addr.setTitle( (*lineIt).value().asString() ); 00571 00572 // TZ 00573 else if ( identifier == "tz" ) { 00574 TimeZone tz; 00575 const TQString date = (*lineIt).value().asString(); 00576 00577 int hours = date.mid( 1, 2).toInt(); 00578 int minutes = date.mid( 4, 2 ).toInt(); 00579 int offset = ( hours * 60 ) + minutes; 00580 offset = offset * ( date[ 0 ] == '+' ? 1 : -1 ); 00581 00582 tz.setOffset( offset ); 00583 addr.setTimeZone( tz ); 00584 } 00585 00586 // UID 00587 else if ( identifier == "uid" ) 00588 addr.setUid( (*lineIt).value().asString() ); 00589 00590 // URI 00591 else if ( identifier == "uri" ) 00592 addr.setUri( (*lineIt).value().asString() ); 00593 00594 // URL 00595 else if ( identifier == "url" ) 00596 addr.setUrl( KURL( (*lineIt).value().asString() ) ); 00597 00598 // X- 00599 else if ( identifier.startsWith( "x-" ) ) { 00600 const TQString key = (*lineIt).identifier().mid( 2 ); 00601 int dash = key.find( "-" ); 00602 addr.insertCustom( key.left( dash ), key.mid( dash + 1 ), (*lineIt).value().asString() ); 00603 } 00604 } 00605 } 00606 00607 addrList.append( addr ); 00608 } 00609 00610 return addrList; 00611 } 00612 00613 TQDateTime VCardTool::parseDateTime(const TQString &str) 00614 { 00615 TQDateTime dateTime; 00616 00617 /* This regex matches one of the following formats (description taken from 00618 https://www.w3.org/TR/NOTE-datetime, copyright remains of the respective documentation author(s)) 00619 Year: YYYY (eg 1997) 00620 Year and month: YYYY-MM (eg 1997-07) 00621 Complete date: YYYY-MM-DD (eg 1997-07-16) 00622 Complete date plus hours and minutes: YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00) 00623 Complete date plus hours, minutes and seconds: YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) 00624 Complete date plus hours, minutes, seconds and a decimal fraction of a second 00625 YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) 00626 where: 00627 YYYY = four-digit year 00628 MM = two-digit month (01=January, etc.) 00629 DD = two-digit day of month (01 through 31) 00630 hh = two digits of hour (00 through 23) (am/pm NOT allowed) 00631 mm = two digits of minute (00 through 59) 00632 ss = two digits of second (00 through 59) 00633 s = one or more digits representing a decimal fraction of a second 00634 TZD = time zone designator (Z or +hh:mm or -hh:mm) 00635 */ 00636 TQRegExp re("(\\d{4})(?:-(\\d{2})(?:-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d+))?)?" 00637 "(?:(Z)|([+-])(\\d{2}):(\\d{2})))?)?)?", true, false); 00638 if (!re.exactMatch(str)) 00639 { 00640 // Try alternative format if pattern does not match 00641 /* This regex matches one of the following formats (description adapted from 00642 https://www.w3.org/TR/NOTE-datetime, copyright remains of the respective documentation author(s)) 00643 Year: YYYY (eg 1997) 00644 Year and month: YYYYMM (eg 199707) 00645 Complete date: YYYYMMDD (eg 19970716) 00646 Complete date plus hours and minutes: YYYYMMDDThhmmTZD (eg 19970716T1920+0100) 00647 Complete date plus hours, minutes and seconds: YYYYMMDDThhmmssTZD (eg 19970716T192030+0100) 00648 Complete date plus hours, minutes, seconds and a decimal fraction of a second 00649 YYYYMMDDThhmmsslTZD (eg 19970716T19203045+0100) 00650 where: 00651 YYYY = four-digit year 00652 MM = two-digit month (01=January, etc.) 00653 DD = two-digit day of month (01 through 31) 00654 hh = two digits of hour (00 through 23) (am/pm NOT allowed) 00655 mm = two digits of minute (00 through 59) 00656 ss = two digits of second (00 through 59) 00657 l = one or more digits representing a decimal fraction of a second 00658 TZD = time zone designator (Z or +hhmm or -hhmm) 00659 */ 00660 re.setPattern("(\\d{4})(?:(\\d{2})(?:(\\d{2})(?:T(\\d{2})(\\d{2})(?:(\\d{2})(?:(\\d+))?)?" 00661 "(?:(Z)|([+-])(\\d{2})(\\d{2})))?)?)?"); 00662 } 00663 if (re.exactMatch(str)) 00664 { 00665 // Insert date 00666 dateTime.setDate(TQDate(re.cap(1).toInt(), // year 00667 !re.cap(2).isEmpty() ? re.cap(2).toInt() : 1, // month 00668 !re.cap(3).isEmpty() ? re.cap(3).toInt() : 1)); // day 00669 if (!re.cap(4).isEmpty()) 00670 { 00671 // Time was also specified 00672 int millis = 0; 00673 if (!re.cap(7).isEmpty()) 00674 { 00675 millis += re.cap(7)[0].isDigit() ? re.cap(7)[0].digitValue() * 100 : 0; 00676 millis += re.cap(7)[1].isDigit() ? re.cap(7)[1].digitValue() * 10 : 0; 00677 millis += re.cap(7)[2].isDigit() ? re.cap(7)[2].digitValue() : 0; 00678 } 00679 dateTime.setTime(TQTime(re.cap(4).toInt(), // hours 00680 re.cap(5).toInt(), // minutes 00681 !re.cap(6).isEmpty() ? re.cap(6).toInt() : 0, // seconds 00682 millis)); // milliseconds 00683 // Add time offset if time not in UTC format 00684 if (!re.cap(9).isEmpty()) 00685 { 00686 int offset = re.cap(10).toInt() * 3600 + re.cap(11).toInt() * 60; 00687 if (re.cap(9) == "+") 00688 { 00689 // Local time zone is ahead of UTC time 00690 offset = -offset; 00691 } 00692 dateTime = dateTime.addSecs(offset); 00693 } 00694 } 00695 } 00696 return dateTime; 00697 } 00698 00699 TQString VCardTool::createDateTime( const TQDateTime &dateTime ) 00700 { 00701 TQString str; 00702 00703 if ( dateTime.date().isValid() ) { 00704 str.sprintf( "%4d-%02d-%02d", dateTime.date().year(), dateTime.date().month(), 00705 dateTime.date().day() ); 00706 if ( dateTime.time().isValid() ) { 00707 TQString tmp; 00708 tmp.sprintf( "T%02d:%02d:%02dZ", dateTime.time().hour(), dateTime.time().minute(), 00709 dateTime.time().second() ); 00710 str += tmp; 00711 } 00712 } 00713 00714 return str; 00715 } 00716 00717 Picture VCardTool::parsePicture( const VCardLine &line ) 00718 { 00719 Picture pic; 00720 00721 const TQStringList params = line.parameterList(); 00722 if ( params.findIndex( "encoding" ) != -1 ) { 00723 TQImage img; 00724 img.loadFromData( line.value().asByteArray() ); 00725 pic.setData( img ); 00726 } else if ( params.findIndex( "value" ) != -1 ) { 00727 if ( line.parameter( "value" ).lower() == "uri" ) 00728 pic.setUrl( line.value().asString() ); 00729 } 00730 00731 if ( params.findIndex( "type" ) != -1 ) 00732 pic.setType( line.parameter( "type" ) ); 00733 00734 return pic; 00735 } 00736 00737 VCardLine VCardTool::createPicture( const TQString &identifier, const Picture &pic ) 00738 { 00739 VCardLine line( identifier ); 00740 00741 if ( pic.isIntern() ) { 00742 if ( !pic.data().isNull() ) { 00743 TQByteArray input; 00744 TQBuffer buffer( input ); 00745 buffer.open( IO_WriteOnly ); 00746 00747 TQImageIO iio( &buffer, "JPEG" ); 00748 iio.setImage( pic.data() ); 00749 iio.setQuality( 100 ); 00750 iio.write(); 00751 00752 line.setValue( input ); 00753 line.addParameter( "encoding", "b" ); 00754 line.addParameter( "type", "image/jpeg" ); 00755 } 00756 } else if ( !pic.url().isEmpty() ) { 00757 line.setValue( pic.url() ); 00758 line.addParameter( "value", "URI" ); 00759 } 00760 00761 return line; 00762 } 00763 00764 Sound VCardTool::parseSound( const VCardLine &line ) 00765 { 00766 Sound snd; 00767 00768 const TQStringList params = line.parameterList(); 00769 if ( params.findIndex( "encoding" ) != -1 ) 00770 snd.setData( line.value().asByteArray() ); 00771 else if ( params.findIndex( "value" ) != -1 ) { 00772 if ( line.parameter( "value" ).lower() == "uri" ) 00773 snd.setUrl( line.value().asString() ); 00774 } 00775 00776 /* TODO: support sound types 00777 if ( params.contains( "type" ) ) 00778 snd.setType( line.parameter( "type" ) ); 00779 */ 00780 00781 return snd; 00782 } 00783 00784 VCardLine VCardTool::createSound( const Sound &snd ) 00785 { 00786 VCardLine line( "SOUND" ); 00787 00788 if ( snd.isIntern() ) { 00789 if ( !snd.data().isEmpty() ) { 00790 line.setValue( snd.data() ); 00791 line.addParameter( "encoding", "b" ); 00792 // TODO: need to store sound type!!! 00793 } 00794 } else if ( !snd.url().isEmpty() ) { 00795 line.setValue( snd.url() ); 00796 line.addParameter( "value", "URI" ); 00797 } 00798 00799 return line; 00800 } 00801 00802 Key VCardTool::parseKey( const VCardLine &line ) 00803 { 00804 Key key; 00805 00806 const TQStringList params = line.parameterList(); 00807 if ( params.findIndex( "encoding" ) != -1 ) 00808 key.setBinaryData( line.value().asByteArray() ); 00809 else 00810 key.setTextData( line.value().asString() ); 00811 00812 if ( params.findIndex( "type" ) != -1 ) { 00813 if ( line.parameter( "type" ).lower() == "x509" ) 00814 key.setType( Key::X509 ); 00815 else if ( line.parameter( "type" ).lower() == "pgp" ) 00816 key.setType( Key::PGP ); 00817 else { 00818 key.setType( Key::Custom ); 00819 key.setCustomTypeString( line.parameter( "type" ) ); 00820 } 00821 } 00822 00823 return key; 00824 } 00825 00826 VCardLine VCardTool::createKey( const Key &key ) 00827 { 00828 VCardLine line( "KEY" ); 00829 00830 if ( key.isBinary() ) { 00831 if ( !key.binaryData().isEmpty() ) { 00832 line.setValue( key.binaryData() ); 00833 line.addParameter( "encoding", "b" ); 00834 } 00835 } else if ( !key.textData().isEmpty() ) 00836 line.setValue( key.textData() ); 00837 00838 if ( key.type() == Key::X509 ) 00839 line.addParameter( "type", "X509" ); 00840 else if ( key.type() == Key::PGP ) 00841 line.addParameter( "type", "PGP" ); 00842 else if ( key.type() == Key::Custom ) 00843 line.addParameter( "type", key.customTypeString() ); 00844 00845 return line; 00846 } 00847 00848 Secrecy VCardTool::parseSecrecy( const VCardLine &line ) 00849 { 00850 Secrecy secrecy; 00851 00852 if ( line.value().asString().lower() == "public" ) 00853 secrecy.setType( Secrecy::Public ); 00854 if ( line.value().asString().lower() == "private" ) 00855 secrecy.setType( Secrecy::Private ); 00856 if ( line.value().asString().lower() == "confidential" ) 00857 secrecy.setType( Secrecy::Confidential ); 00858 00859 return secrecy; 00860 } 00861 00862 VCardLine VCardTool::createSecrecy( const Secrecy &secrecy ) 00863 { 00864 VCardLine line( "CLASS" ); 00865 00866 int type = secrecy.type(); 00867 00868 if ( type == Secrecy::Public ) 00869 line.setValue( "PUBLIC" ); 00870 else if ( type == Secrecy::Private ) 00871 line.setValue( "PRIVATE" ); 00872 else if ( type == Secrecy::Confidential ) 00873 line.setValue( "CONFIDENTIAL" ); 00874 00875 return line; 00876 } 00877 00878 Agent VCardTool::parseAgent( const VCardLine &line ) 00879 { 00880 Agent agent; 00881 00882 const TQStringList params = line.parameterList(); 00883 if ( params.findIndex( "value" ) != -1 ) { 00884 if ( line.parameter( "value" ).lower() == "uri" ) 00885 agent.setUrl( line.value().asString() ); 00886 } else { 00887 TQString str = line.value().asString(); 00888 str.replace( "\\n", "\r\n" ); 00889 str.replace( "\\N", "\r\n" ); 00890 str.replace( "\\;", ";" ); 00891 str.replace( "\\:", ":" ); 00892 str.replace( "\\,", "," ); 00893 00894 const Addressee::List list = parseVCards( str ); 00895 if ( list.count() > 0 ) { 00896 Addressee *addr = new Addressee; 00897 *addr = list[ 0 ]; 00898 agent.setAddressee( addr ); 00899 } 00900 } 00901 00902 return agent; 00903 } 00904 00905 VCardLine VCardTool::createAgent( VCard::Version version, const Agent &agent ) 00906 { 00907 VCardLine line( "AGENT" ); 00908 00909 if ( agent.isIntern() ) { 00910 if ( agent.addressee() != 0 ) { 00911 Addressee::List list; 00912 list.append( *agent.addressee() ); 00913 00914 TQString str = createVCards( list, version ); 00915 str.replace( "\r\n", "\\n" ); 00916 str.replace( ";", "\\;" ); 00917 str.replace( ":", "\\:" ); 00918 str.replace( ",", "\\," ); 00919 line.setValue( str ); 00920 } 00921 } else if ( !agent.url().isEmpty() ) { 00922 line.setValue( agent.url() ); 00923 line.addParameter( "value", "URI" ); 00924 } 00925 00926 return line; 00927 } 00928 00929 TQStringList VCardTool::splitString( const TQChar &sep, const TQString &str ) 00930 { 00931 TQStringList list; 00932 TQString value( str ); 00933 00934 int start = 0; 00935 int pos = value.find( sep, start ); 00936 00937 while ( pos != -1 ) { 00938 if ( value[ pos - 1 ] != '\\' ) { 00939 if ( pos > start && pos <= (int)value.length() ) 00940 list << value.mid( start, pos - start ); 00941 else 00942 list << TQString::null; 00943 00944 start = pos + 1; 00945 pos = value.find( sep, start ); 00946 } else { 00947 if ( pos != 0 ) { 00948 value.replace( pos - 1, 2, sep ); 00949 pos = value.find( sep, pos ); 00950 } else 00951 pos = value.find( sep, pos + 1 ); 00952 } 00953 } 00954 00955 int l = value.length() - 1; 00956 if ( value.mid( start, l - start + 1 ).length() > 0 ) 00957 list << value.mid( start, l - start + 1 ); 00958 else 00959 list << TQString::null; 00960 00961 return list; 00962 }