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>
53 #include <klocalizedstring.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 );
196 QString KTnef::msTNEFToVPart(
const QByteArray &tnef )
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
537 QString KTnef::formatTNEFInvitation(
const QByteArray &tnef,
539 KCal::InvitationFormatterHelper *h )
543 if ( !iCal.isEmpty() ) {
551 QString KTnef::formatTNEFInvitation(
const QByteArray &tnef,
552 const MemoryCalendar::Ptr &cal,
553 KCalUtils::InvitationFormatterHelper *h )
556 QString iCal = KCalUtils::IncidenceFormatter::formatICalInvitation( vPart, cal, h,
true );
557 if ( !iCal.isEmpty() ) {
QString findProp(int key, const QString &fallback=QString(), bool convertToUpper=false) const
Finds a property by key, returning a formatted value.
This file is part of the API for handling TNEF data and defines the KTNEFMessage class.
Represents a TNEF message.
This file is part of the API for handling TNEF data and provides some basic definitions for general u...
This file is part of the API for handling TNEF data and defines the KTNEFParser class.
QString findNamedProp(const QString &name, const QString &fallback=QString(), bool convertToUpper=false) const
Finds a property by name, returning a formatted value.
bool openDevice(QIODevice *device)
Opens the #QIODevice device for parsing.
KTNEFMessage * message() const
Returns the KTNEFMessage used in the parsing process.