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