40 #include <kpimutils/email.h>
41 #include <kabc/phonenumber.h>
42 #include <kabc/vcardconverter.h>
44 #ifndef KDEPIM_NO_KCAL
49 #include <kcalcore/calendar.h>
50 #include <kcalcore/icalformat.h>
51 #include <kcalutils/incidenceformatter.h>
54 #include <kdatetime.h>
56 #include <QtCore/QBuffer>
60 using namespace KCalCore;
61 using namespace KTnef;
69 static QString stringProp(
KTNEFMessage *tnefMsg,
const quint32 &key,
70 const QString &fallback = QString() )
72 return tnefMsg->
findProp( key < 0x10000 ? key & 0xFFFF : key >> 16, fallback );
75 static QString sNamedProp(
KTNEFMessage *tnefMsg,
const QString &name,
76 const QString &fallback = QString() )
87 static struct save_tz set_tz( const char *_tc )
89 const char *tc = _tc?_tc:
"UTC";
99 if ( !qgetenv(
"TZ" ).isEmpty() ) {
100 tz_env = qstrdup( qgetenv(
"TZ" ) );
103 char *tmp_env = (
char*)malloc( strlen( tc ) + 4 );
104 strcpy( tmp_env,
"TZ=" );
105 strcpy( tmp_env+3, tc );
108 rv.tz_env_str = tmp_env;
119 static void unset_tz(
struct save_tz old_tz )
121 if ( old_tz.old_tz ) {
122 char *tmp_env = (
char*)malloc( strlen( old_tz.old_tz ) + 4 );
123 strcpy( tmp_env,
"TZ=" );
124 strcpy( tmp_env+3, old_tz.old_tz );
127 free( old_tz.old_tz );
130 putenv( strdup(
"TZ" ) );
135 if ( old_tz.tz_env_str ) {
136 free( old_tz.tz_env_str );
140 static KDateTime utc2Local(
const KDateTime &utcdt )
144 save_tz tmp_tz = set_tz(
"UTC" );
145 time_t utc = utcdt.toTime_t();
148 localtime_r( &utc, &tmL );
149 return KDateTime( QDate( tmL.tm_year + 1900, tmL.tm_mon + 1, tmL.tm_mday ),
150 QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
153 static KDateTime pureISOToLocalQDateTime(
const QString &dtStr,
154 bool bDateOnly =
false )
158 int year, month, day, hour, minute, second;
161 year = dtStr.left( 4 ).toInt();
162 month = dtStr.mid( 4, 2 ).toInt();
163 day = dtStr.mid( 6, 2 ).toInt();
168 year = dtStr.left( 4 ).toInt();
169 month = dtStr.mid( 4, 2 ).toInt();
170 day = dtStr.mid( 6, 2 ).toInt();
171 hour = dtStr.mid( 9, 2 ).toInt();
172 minute = dtStr.mid( 11, 2 ).toInt();
173 second = dtStr.mid( 13, 2 ).toInt();
175 tmpDate.setYMD( year, month, day );
176 tmpTime.setHMS( hour, minute, second );
178 if ( tmpDate.isValid() && tmpTime.isValid() ) {
179 KDateTime dT = KDateTime( tmpDate, tmpTime );
183 if ( dtStr.at( dtStr.length() - 1 ) ==
'Z' ) {
186 dT = utc2Local( dT );
201 QByteArray b( tnef );
203 MemoryCalendar::Ptr cal(
new MemoryCalendar( KDateTime::UTC ) );
204 KABC::Addressee addressee;
205 ICalFormat calFormat;
206 Event::Ptr event(
new Event() );
214 QString msgClass = tnefMsg->
findProp( 0x001A, QString(),
true ).toUpper();
215 if ( !msgClass.isEmpty() ) {
218 bool bCompatClassAppointment =
false;
219 bool bCompatMethodRequest =
false;
220 bool bCompatMethodCancled =
false;
221 bool bCompatMethodAccepted =
false;
222 bool bCompatMethodAcceptedCond =
false;
223 bool bCompatMethodDeclined =
false;
224 if ( msgClass.startsWith( QLatin1String(
"IPM.MICROSOFT SCHEDULE." ) ) ) {
225 bCompatClassAppointment =
true;
226 if ( msgClass.endsWith( QLatin1String(
".MTGREQ" ) ) ) {
227 bCompatMethodRequest =
true;
229 if ( msgClass.endsWith( QLatin1String(
".MTGCNCL" ) ) ) {
230 bCompatMethodCancled =
true;
232 if ( msgClass.endsWith( QLatin1String(
".MTGRESPP" ) ) ) {
233 bCompatMethodAccepted =
true;
235 if ( msgClass.endsWith( QLatin1String(
".MTGRESPA" ) ) ) {
236 bCompatMethodAcceptedCond =
true;
238 if ( msgClass.endsWith( QLatin1String(
".MTGRESPN" ) ) ) {
239 bCompatMethodDeclined =
true;
242 bool bCompatClassNote = ( msgClass ==
"IPM.MICROSOFT MAIL.NOTE" );
244 if ( bCompatClassAppointment ||
"IPM.APPOINTMENT" == msgClass ) {
246 bool bIsReply =
false;
247 QString prodID =
"-//Microsoft Corporation//Outlook ";
249 prodID +=
"MIMEDIR/EN\n";
250 prodID +=
"VERSION:2.0\n";
251 calFormat.setApplication(
"Outlook", prodID );
254 if ( bCompatMethodRequest ) {
255 method = iTIPRequest;
256 }
else if ( bCompatMethodCancled ) {
258 }
else if ( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
259 bCompatMethodDeclined ) {
271 if ( tnefMsg->
findProp(0x0c17) ==
"1" ) {
274 method = iTIPRequest;
278 ScheduleMessage schedMsg( event, method, ScheduleMessage::Unknown );
280 QString sSenderSearchKeyEmail( tnefMsg->
findProp( 0x0C1D ) );
282 if ( !sSenderSearchKeyEmail.isEmpty() ) {
283 int colon = sSenderSearchKeyEmail.indexOf(
':' );
285 if ( sSenderSearchKeyEmail.indexOf(
':' ) == -1 ) {
286 sSenderSearchKeyEmail.remove( 0, colon+1 );
290 QString s( tnefMsg->
findProp( 0x8189 ) );
291 const QStringList attendees = s.split(
';' );
292 if ( attendees.count() ) {
293 for ( QStringList::const_iterator it = attendees.begin();
294 it != attendees.end(); ++it ) {
297 if ( (*it).indexOf(
'@' ) == -1 ) {
300 Attendee::Ptr attendee(
new Attendee( s, s,
true ) );
302 if ( bCompatMethodAccepted ) {
303 attendee->setStatus( Attendee::Accepted );
305 if ( bCompatMethodDeclined ) {
306 attendee->setStatus( Attendee::Declined );
308 if ( bCompatMethodAcceptedCond ) {
309 attendee->setStatus( Attendee::Tentative );
312 attendee->setStatus( Attendee::NeedsAction );
313 attendee->setRole( Attendee::ReqParticipant );
315 event->addAttendee( attendee );
321 s = sSenderSearchKeyEmail;
322 if ( !s.isEmpty() ) {
323 Attendee::Ptr attendee(
new Attendee( QString(), QString(),
true ) );
325 if ( bCompatMethodAccepted ) {
326 attendee->setStatus( Attendee::Accepted );
328 if ( bCompatMethodAcceptedCond ) {
329 attendee->setStatus( Attendee::Declined );
331 if ( bCompatMethodDeclined ) {
332 attendee->setStatus( Attendee::Tentative );
335 attendee->setStatus( Attendee::NeedsAction );
336 attendee->setRole( Attendee::ReqParticipant );
338 event->addAttendee( attendee );
342 if ( s.isEmpty() && !bIsReply ) {
343 s = sSenderSearchKeyEmail;
346 if ( !s.isEmpty() ) {
347 event->setOrganizer( s );
350 s = tnefMsg->
findProp( 0x819b ).remove( QChar(
'-' ) ).remove( QChar(
':' ) );
351 event->setDtStart( KDateTime::fromString( s ) );
353 s = tnefMsg->
findProp( 0x819c ).remove( QChar(
'-' ) ).remove( QChar(
':' ) );
354 event->setDtEnd( KDateTime::fromString( s ) );
357 event->setLocation( s );
369 s = tnefMsg->
findProp( 0x8202 ).remove( QChar(
'-' ) ).remove( QChar(
':' ) );
374 event->setCategories( s );
377 event->setDescription( s );
380 event->setSummary( s );
383 event->setPriority( s.toInt() );
385 if ( !tnefMsg->
findProp( 0x8503 ).isEmpty() ) {
386 Alarm::Ptr alarm(
new Alarm( event.data() ) );
387 KDateTime highNoonTime =
388 pureISOToLocalQDateTime( tnefMsg->
findProp( 0x8502 ).
389 remove( QChar(
'-' ) ).
remove( QChar(
':' ) ) );
390 KDateTime wakeMeUpTime =
391 pureISOToLocalQDateTime( tnefMsg->
findProp( 0x8560,
"" ).
392 remove( QChar(
'-' ) ).
remove( QChar(
':' ) ) );
393 alarm->setTime( wakeMeUpTime );
395 if ( highNoonTime.isValid() && wakeMeUpTime.isValid() ) {
396 alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
399 alarm->setStartOffset( Duration( 15 * 60 ) );
401 alarm->setDisplayAlarm( i18n(
"Reminder" ) );
405 event->addAlarm( alarm );
408 if ( event->uid().isEmpty() ) {
409 event->setUid( CalFormat::createUniqueId() );
411 cal->addEvent( event );
414 }
else if ( bCompatClassNote ||
"IPM.CONTACT" == msgClass ) {
415 addressee.setUid( stringProp( tnefMsg, attMSGID ) );
416 addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
417 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ),
true );
418 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ),
false );
419 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ),
false );
420 addressee.insertCustom(
"KADDRESSBOOK",
"X-IMAddress",
421 sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
422 addressee.insertCustom(
"KADDRESSBOOK",
"X-SpousesName",
423 stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
424 addressee.insertCustom(
"KADDRESSBOOK",
"X-ManagersName",
425 stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
426 addressee.insertCustom(
"KADDRESSBOOK",
"X-AssistantsName",
427 stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
428 addressee.insertCustom(
"KADDRESSBOOK",
"X-Department",
429 stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
430 addressee.insertCustom(
"KADDRESSBOOK",
"X-Office",
431 stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
432 addressee.insertCustom(
"KADDRESSBOOK",
"X-Profession",
433 stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
435 QString s = tnefMsg->
findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY ).
436 remove( QChar(
'-' ) ).
remove( QChar(
':' ) );
437 if ( !s.isEmpty() ) {
438 addressee.insertCustom(
"KADDRESSBOOK",
"X-Anniversary", s );
441 addressee.setUrl( KUrl( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) );
444 addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
445 addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
446 addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
447 addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
448 addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
450 addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
451 addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
452 addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
459 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
460 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
461 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
462 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
463 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
464 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
465 adr.setType( KABC::Address::Home );
466 addressee.insertAddress( adr );
468 adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
469 adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
470 adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
471 adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
472 adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
473 adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
474 adr.setType( KABC::Address::Work );
475 addressee.insertAddress( adr );
477 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
478 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
479 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
480 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
481 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
482 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
483 adr.setType( KABC::Address::Dom );
484 addressee.insertAddress( adr );
493 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
494 addressee.insertPhoneNumber(
495 KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) );
496 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
497 addressee.insertPhoneNumber(
498 KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) );
499 nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
500 addressee.insertPhoneNumber(
501 KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) );
502 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
503 addressee.insertPhoneNumber(
504 KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) );
505 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
506 addressee.insertPhoneNumber(
507 KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) );
509 s = tnefMsg->
findProp( MAPI_TAG_PR_BIRTHDAY ).
510 remove( QChar(
'-' ) ).
remove( QChar(
':' ) );
511 if ( !s.isEmpty() ) {
512 addressee.setBirthday( QDateTime::fromString( s ) );
515 bOk = ( !addressee.isEmpty() );
516 }
else if (
"IPM.NOTE" == msgClass ) {
525 const QString iCal = calFormat.toString( cal, QString() );
526 if ( !iCal.isEmpty() ) {
532 KABC::VCardConverter converter;
533 return QString::fromUtf8( converter.createVCard( addressee ) );
536 #ifndef KDEPIM_NO_KCAL
539 KCal::InvitationFormatterHelper *h )
542 QString iCal = KCal::IncidenceFormatter::formatICalInvitation( vPart, cal, h );
543 if ( !iCal.isEmpty() ) {
552 const MemoryCalendar::Ptr &cal,
553 KCalUtils::InvitationFormatterHelper *h )
556 QString iCal = KCalUtils::IncidenceFormatter::formatICalInvitation( vPart, cal, h,
true );
557 if ( !iCal.isEmpty() ) {