KTNEF Library
formatter.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> 00003 Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com> 00004 Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 */ 00035 #include "formatter.h" 00036 #include "ktnefparser.h" 00037 #include "ktnefmessage.h" 00038 #include "ktnefdefs.h" 00039 00040 #include <kpimutils/email.h> 00041 #include <kabc/phonenumber.h> 00042 #include <kabc/vcardconverter.h> 00043 #include <kcal/incidenceformatter.h> 00044 #include <kcal/calendar.h> 00045 #include <kcal/calendarlocal.h> 00046 #include <kcal/icalformat.h> 00047 00048 #include <klocale.h> 00049 #include <kdatetime.h> 00050 00051 #include <QtCore/QBuffer> 00052 00053 #include <time.h> 00054 00055 using namespace KCal; 00056 using namespace KTnef; 00057 00058 /******************************************************************* 00059 * Helper functions for the msTNEF -> VPart converter 00060 *******************************************************************/ 00061 00062 //----------------------------------------------------------------------------- 00063 //@cond IGNORE 00064 static QString stringProp( KTNEFMessage *tnefMsg, const quint32 &key, 00065 const QString &fallback = QString() ) 00066 { 00067 return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16, fallback ); 00068 } 00069 00070 static QString sNamedProp( KTNEFMessage *tnefMsg, const QString &name, 00071 const QString &fallback = QString() ) 00072 { 00073 return tnefMsg->findNamedProp( name, fallback ); 00074 } 00075 00076 struct save_tz { 00077 char *old_tz; 00078 char *tz_env_str; 00079 }; 00080 00081 /* temporarily go to a different timezone */ 00082 static struct save_tz set_tz( const char *_tc ) 00083 { 00084 const char *tc = _tc?_tc:"UTC"; 00085 00086 struct save_tz rv; 00087 00088 rv.old_tz = 0; 00089 rv.tz_env_str = 0; 00090 00091 //kDebug() << "set_tz(), timezone before =" << timezone; 00092 00093 char *tz_env = 0; 00094 if ( !qgetenv( "TZ" ).isEmpty() ) { 00095 tz_env = qstrdup( qgetenv( "TZ" ) ); 00096 rv.old_tz = tz_env; 00097 } 00098 char *tmp_env = (char*)malloc( strlen( tc ) + 4 ); 00099 strcpy( tmp_env, "TZ=" ); 00100 strcpy( tmp_env+3, tc ); 00101 putenv( tmp_env ); 00102 00103 rv.tz_env_str = tmp_env; 00104 00105 /* tmp_env is not free'ed -- it is part of the environment */ 00106 00107 tzset(); 00108 //kDebug() << "set_tz(), timezone after =" << timezone; 00109 00110 return rv; 00111 } 00112 00113 /* restore previous timezone */ 00114 static void unset_tz( struct save_tz old_tz ) 00115 { 00116 if ( old_tz.old_tz ) { 00117 char *tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 ); 00118 strcpy( tmp_env, "TZ=" ); 00119 strcpy( tmp_env+3, old_tz.old_tz ); 00120 putenv( tmp_env ); 00121 /* tmp_env is not free'ed -- it is part of the environment */ 00122 free( old_tz.old_tz ); 00123 } else { 00124 /* clear TZ from env */ 00125 putenv( strdup( "TZ" ) ); 00126 } 00127 tzset(); 00128 00129 /* is this OK? */ 00130 if ( old_tz.tz_env_str ) { 00131 free( old_tz.tz_env_str ); 00132 } 00133 } 00134 00135 static KDateTime utc2Local( const KDateTime &utcdt ) 00136 { 00137 struct tm tmL; 00138 00139 save_tz tmp_tz = set_tz( "UTC" ); 00140 time_t utc = utcdt.toTime_t(); 00141 unset_tz( tmp_tz ); 00142 00143 localtime_r( &utc, &tmL ); 00144 return KDateTime( QDate( tmL.tm_year + 1900, tmL.tm_mon + 1, tmL.tm_mday ), 00145 QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) ); 00146 } 00147 00148 static KDateTime pureISOToLocalQDateTime( const QString &dtStr, 00149 bool bDateOnly = false ) 00150 { 00151 QDate tmpDate; 00152 QTime tmpTime; 00153 int year, month, day, hour, minute, second; 00154 00155 if ( bDateOnly ) { 00156 year = dtStr.left( 4 ).toInt(); 00157 month = dtStr.mid( 4, 2 ).toInt(); 00158 day = dtStr.mid( 6, 2 ).toInt(); 00159 hour = 0; 00160 minute = 0; 00161 second = 0; 00162 } else { 00163 year = dtStr.left( 4 ).toInt(); 00164 month = dtStr.mid( 4, 2 ).toInt(); 00165 day = dtStr.mid( 6, 2 ).toInt(); 00166 hour = dtStr.mid( 9, 2 ).toInt(); 00167 minute = dtStr.mid( 11, 2 ).toInt(); 00168 second = dtStr.mid( 13, 2 ).toInt(); 00169 } 00170 tmpDate.setYMD( year, month, day ); 00171 tmpTime.setHMS( hour, minute, second ); 00172 00173 if ( tmpDate.isValid() && tmpTime.isValid() ) { 00174 KDateTime dT = KDateTime( tmpDate, tmpTime ); 00175 00176 if ( !bDateOnly ) { 00177 // correct for GMT ( == Zulu time == UTC ) 00178 if ( dtStr.at( dtStr.length() - 1 ) == 'Z' ) { 00179 //dT = dT.addSecs( 60 * KRFCDate::localUTCOffset() ); 00180 //localUTCOffset( dT ) ); 00181 dT = utc2Local( dT ); 00182 } 00183 } 00184 return dT; 00185 } else { 00186 return KDateTime(); 00187 } 00188 } 00189 //@endcond 00190 00191 QString KTnef::msTNEFToVPart( const QByteArray &tnef ) 00192 { 00193 bool bOk = false; 00194 00195 KTNEFParser parser; 00196 QByteArray b( tnef ); 00197 QBuffer buf( &b ); 00198 CalendarLocal cal ( KDateTime::UTC ); 00199 KABC::Addressee addressee; 00200 ICalFormat calFormat; 00201 Event *event = new Event(); 00202 00203 if ( parser.openDevice( &buf ) ) { 00204 KTNEFMessage *tnefMsg = parser.message(); 00205 //QMap<int,KTNEFProperty*> props = parser.message()->properties(); 00206 00207 // Everything depends from property PR_MESSAGE_CLASS 00208 // (this is added by KTNEFParser): 00209 QString msgClass = tnefMsg->findProp( 0x001A, QString(), true ).toUpper(); 00210 if ( !msgClass.isEmpty() ) { 00211 // Match the old class names that might be used by Outlook for 00212 // compatibility with Microsoft Mail for Windows for Workgroups 3.1. 00213 bool bCompatClassAppointment = false; 00214 bool bCompatMethodRequest = false; 00215 bool bCompatMethodCancled = false; 00216 bool bCompatMethodAccepted = false; 00217 bool bCompatMethodAcceptedCond = false; 00218 bool bCompatMethodDeclined = false; 00219 if ( msgClass.startsWith( QLatin1String( "IPM.MICROSOFT SCHEDULE." ) ) ) { 00220 bCompatClassAppointment = true; 00221 if ( msgClass.endsWith( QLatin1String( ".MTGREQ" ) ) ) { 00222 bCompatMethodRequest = true; 00223 } 00224 if ( msgClass.endsWith( QLatin1String( ".MTGCNCL" ) ) ) { 00225 bCompatMethodCancled = true; 00226 } 00227 if ( msgClass.endsWith( QLatin1String( ".MTGRESPP" ) ) ) { 00228 bCompatMethodAccepted = true; 00229 } 00230 if ( msgClass.endsWith( QLatin1String( ".MTGRESPA" ) ) ) { 00231 bCompatMethodAcceptedCond = true; 00232 } 00233 if ( msgClass.endsWith( QLatin1String( ".MTGRESPN" ) ) ) { 00234 bCompatMethodDeclined = true; 00235 } 00236 } 00237 bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" ); 00238 00239 if ( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) { 00240 // Compose a vCal 00241 bool bIsReply = false; 00242 QString prodID = "-//Microsoft Corporation//Outlook "; 00243 prodID += tnefMsg->findNamedProp( "0x8554", "9.0" ); 00244 prodID += "MIMEDIR/EN\n"; 00245 prodID += "VERSION:2.0\n"; 00246 calFormat.setApplication( "Outlook", prodID ); 00247 00248 iTIPMethod method; 00249 if ( bCompatMethodRequest ) { 00250 method = iTIPRequest; 00251 } else if ( bCompatMethodCancled ) { 00252 method = iTIPCancel; 00253 } else if ( bCompatMethodAccepted || bCompatMethodAcceptedCond || 00254 bCompatMethodDeclined ) { 00255 method = iTIPReply; 00256 bIsReply = true; 00257 } else { 00258 // pending(khz): verify whether "0x0c17" is the right tag ??? 00259 // 00260 // at the moment we think there are REQUESTS and UPDATES 00261 // 00262 // but WHAT ABOUT REPLIES ??? 00263 // 00264 // 00265 00266 if ( tnefMsg->findProp(0x0c17) == "1" ) { 00267 bIsReply = true; 00268 } 00269 method = iTIPRequest; 00270 } 00271 00273 ScheduleMessage schedMsg( event, method, ScheduleMessage::Unknown ); 00274 00275 QString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) ); 00276 00277 if ( !sSenderSearchKeyEmail.isEmpty() ) { 00278 int colon = sSenderSearchKeyEmail.indexOf( ':' ); 00279 // May be e.g. "SMTP:KHZ@KDE.ORG" 00280 if ( sSenderSearchKeyEmail.indexOf( ':' ) == -1 ) { 00281 sSenderSearchKeyEmail.remove( 0, colon+1 ); 00282 } 00283 } 00284 00285 QString s( tnefMsg->findProp( 0x0e04 ) ); 00286 const QStringList attendees = s.split( ';' ); 00287 if ( attendees.count() ) { 00288 for ( QStringList::const_iterator it = attendees.begin(); 00289 it != attendees.end(); ++it ) { 00290 // Skip all entries that have no '@' since these are 00291 // no mail addresses 00292 if ( (*it).indexOf( '@' ) == -1 ) { 00293 s = (*it).trimmed(); 00294 00295 Attendee *attendee = new Attendee( s, s, true ); 00296 if ( bIsReply ) { 00297 if ( bCompatMethodAccepted ) { 00298 attendee->setStatus( Attendee::Accepted ); 00299 } 00300 if ( bCompatMethodDeclined ) { 00301 attendee->setStatus( Attendee::Declined ); 00302 } 00303 if ( bCompatMethodAcceptedCond ) { 00304 attendee->setStatus( Attendee::Tentative ); 00305 } 00306 } else { 00307 attendee->setStatus( Attendee::NeedsAction ); 00308 attendee->setRole( Attendee::ReqParticipant ); 00309 } 00310 event->addAttendee( attendee ); 00311 } 00312 } 00313 } else { 00314 // Oops, no attendees? 00315 // This must be old style, let us use the PR_SENDER_SEARCH_KEY. 00316 s = sSenderSearchKeyEmail; 00317 if ( !s.isEmpty() ) { 00318 Attendee *attendee = new Attendee( QString(), QString(), true ); 00319 if ( bIsReply ) { 00320 if ( bCompatMethodAccepted ) { 00321 attendee->setStatus( Attendee::Accepted ); 00322 } 00323 if ( bCompatMethodAcceptedCond ) { 00324 attendee->setStatus( Attendee::Declined ); 00325 } 00326 if ( bCompatMethodDeclined ) { 00327 attendee->setStatus( Attendee::Tentative ); 00328 } 00329 } else { 00330 attendee->setStatus( Attendee::NeedsAction ); 00331 attendee->setRole( Attendee::ReqParticipant ); 00332 } 00333 event->addAttendee( attendee ); 00334 } 00335 } 00336 s = tnefMsg->findProp( 0x0c1f ); // look for organizer property 00337 if ( s.isEmpty() && !bIsReply ) { 00338 s = sSenderSearchKeyEmail; 00339 } 00340 // TODO: Use the common name? 00341 if ( !s.isEmpty() ) { 00342 event->setOrganizer( s ); 00343 } 00344 00345 s = tnefMsg->findProp( 0x8516 ).remove( QChar( '-' ) ).remove( QChar( ':' ) ); 00346 event->setDtStart( KDateTime::fromString( s ) ); // ## Format?? 00347 00348 s = tnefMsg->findProp( 0x8517 ).remove( QChar( '-' ) ).remove( QChar( ':' ) ); 00349 event->setDtEnd( KDateTime::fromString( s ) ); 00350 00351 s = tnefMsg->findProp( 0x8208 ); 00352 event->setLocation( s ); 00353 00354 // is it OK to set this to OPAQUE always ?? 00355 //vPart += "TRANSP:OPAQUE\n"; ###FIXME, portme! 00356 //vPart += "SEQUENCE:0\n"; 00357 00358 // is "0x0023" OK - or should we look for "0x0003" ?? 00359 s = tnefMsg->findProp( 0x0023 ); 00360 event->setUid( s ); 00361 00362 // PENDING(khz): is this value in local timezone? Must it be 00363 // adjusted? Most likely this is a bug in the server or in 00364 // Outlook - we ignore it for now. 00365 s = tnefMsg->findProp( 0x8202 ).remove( QChar( '-' ) ).remove( QChar( ':' ) ); 00366 // ### kcal always uses currentDateTime() 00367 // event->setDtStamp( QDateTime::fromString( s ) ); 00368 00369 s = tnefMsg->findNamedProp( "Keywords" ); 00370 event->setCategories( s ); 00371 00372 s = tnefMsg->findProp( 0x1000 ); 00373 event->setDescription( s ); 00374 00375 s = tnefMsg->findProp( 0x0070 ); 00376 event->setSummary( s ); 00377 00378 s = tnefMsg->findProp( 0x0026 ); 00379 event->setPriority( s.toInt() ); 00380 00381 // is reminder flag set ? 00382 if ( !tnefMsg->findProp( 0x8503 ).isEmpty() ) { 00383 Alarm *alarm = new Alarm( event ); 00384 KDateTime highNoonTime = 00385 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8502 ). 00386 remove( QChar( '-' ) ).remove( QChar( ':' ) ) ); 00387 KDateTime wakeMeUpTime = 00388 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8560, "" ). 00389 remove( QChar( '-' ) ).remove( QChar( ':' ) ) ); 00390 alarm->setTime( wakeMeUpTime ); 00391 00392 if ( highNoonTime.isValid() && wakeMeUpTime.isValid() ) { 00393 alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) ); 00394 } else { 00395 // default: wake them up 15 minutes before the appointment 00396 alarm->setStartOffset( Duration( 15 * 60 ) ); 00397 } 00398 alarm->setDisplayAlarm( i18n( "Reminder" ) ); 00399 00400 // Sorry: the different action types are not known (yet) 00401 // so we always set 'DISPLAY' (no sounds, no images...) 00402 event->addAlarm( alarm ); 00403 } 00404 cal.addEvent( event ); 00405 bOk = true; 00406 // we finished composing a vCal 00407 } else if ( bCompatClassNote || "IPM.CONTACT" == msgClass ) { 00408 addressee.setUid( stringProp( tnefMsg, attMSGID ) ); 00409 addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) ); 00410 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true ); 00411 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false ); 00412 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false ); 00413 addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", 00414 sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) ); 00415 addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", 00416 stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) ); 00417 addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", 00418 stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) ); 00419 addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", 00420 stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) ); 00421 addressee.insertCustom( "KADDRESSBOOK", "X-Department", 00422 stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) ); 00423 addressee.insertCustom( "KADDRESSBOOK", "X-Office", 00424 stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) ); 00425 addressee.insertCustom( "KADDRESSBOOK", "X-Profession", 00426 stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) ); 00427 00428 QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY ). 00429 remove( QChar( '-' ) ).remove( QChar( ':' ) ); 00430 if ( !s.isEmpty() ) { 00431 addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s ); 00432 } 00433 00434 addressee.setUrl( KUrl( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) ); 00435 00436 // collect parts of Name entry 00437 addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) ); 00438 addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) ); 00439 addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) ); 00440 addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) ); 00441 addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) ); 00442 00443 addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) ); 00444 addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) ); 00445 addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) ); 00446 /* 00447 the MAPI property ID of this (multiline) )field is unknown: 00448 vPart += stringProp(tnefMsg, "\n","NOTE", ... , "" ); 00449 */ 00450 00451 KABC::Address adr; 00452 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) ); 00453 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) ); 00454 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) ); 00455 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) ); 00456 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) ); 00457 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) ); 00458 adr.setType( KABC::Address::Home ); 00459 addressee.insertAddress( adr ); 00460 00461 adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) ); 00462 adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) ); 00463 adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) ); 00464 adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) ); 00465 adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) ); 00466 adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) ); 00467 adr.setType( KABC::Address::Work ); 00468 addressee.insertAddress( adr ); 00469 00470 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) ); 00471 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) ); 00472 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) ); 00473 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) ); 00474 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) ); 00475 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) ); 00476 adr.setType( KABC::Address::Dom ); 00477 addressee.insertAddress( adr ); 00478 00479 // problem: the 'other' address was stored by KOrganizer in 00480 // a line looking like the following one: 00481 // vPart += "\nADR;TYPE=dom;TYPE=intl;TYPE=parcel;TYPE=postal;TYPE=work;" 00482 // "TYPE=home:other_pobox;;other_str1\nother_str2;other_loc;other_region;" 00483 // "other_pocode;other_country" 00484 00485 QString nr; 00486 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER ); 00487 addressee.insertPhoneNumber( 00488 KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) ); 00489 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER ); 00490 addressee.insertPhoneNumber( 00491 KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) ); 00492 nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER ); 00493 addressee.insertPhoneNumber( 00494 KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) ); 00495 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER ); 00496 addressee.insertPhoneNumber( 00497 KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) ); 00498 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER ); 00499 addressee.insertPhoneNumber( 00500 KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) ); 00501 00502 s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY ). 00503 remove( QChar( '-' ) ).remove( QChar( ':' ) ); 00504 if ( !s.isEmpty() ) { 00505 addressee.setBirthday( QDateTime::fromString( s ) ); 00506 } 00507 00508 bOk = ( !addressee.isEmpty() ); 00509 } else if ( "IPM.NOTE" == msgClass ) { 00510 00511 } // else if ... and so on ... 00512 } 00513 } 00514 00515 // Compose return string 00516 QString iCal = calFormat.toString( &cal ); 00517 if ( !iCal.isEmpty() ) { 00518 // This was an iCal 00519 return iCal; 00520 } 00521 00522 // Not an iCal - try a vCard 00523 KABC::VCardConverter converter; 00524 return QString::fromUtf8( converter.createVCard( addressee ) ); 00525 } 00526 00527 QString KTnef::formatTNEFInvitation( const QByteArray &tnef, 00528 KCal::Calendar *cal, 00529 KCal::InvitationFormatterHelper *h ) 00530 { 00531 QString vPart = msTNEFToVPart( tnef ); 00532 QString iCal = IncidenceFormatter::formatICalInvitation( vPart, cal, h ); 00533 if ( !iCal.isEmpty() ) { 00534 return iCal; 00535 } else { 00536 return vPart; 00537 } 00538 } 00539