00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "incidenceformatter.h"
00023
00024 #include <libkcal/attachment.h>
00025 #include <libkcal/event.h>
00026 #include <libkcal/todo.h>
00027 #include <libkcal/journal.h>
00028 #include <libkcal/calendar.h>
00029 #include <libkcal/calendarlocal.h>
00030 #include <libkcal/icalformat.h>
00031 #include <libkcal/freebusy.h>
00032
00033 #include <libkdepim/email.h>
00034
00035 #include <ktnef/ktnefparser.h>
00036 #include <ktnef/ktnefmessage.h>
00037 #include <ktnef/ktnefdefs.h>
00038 #include <kabc/phonenumber.h>
00039 #include <kabc/vcardconverter.h>
00040 #include <kabc/stdaddressbook.h>
00041
00042 #include <kapplication.h>
00043
00044
00045 #include <klocale.h>
00046 #include <kiconloader.h>
00047
00048 #include <qbuffer.h>
00049
00050 #include <time.h>
00051
00052
00053 using namespace KCal;
00054
00055
00056 static QString stringProp( KTNEFMessage* tnefMsg, const Q_UINT32& key,
00057 const QString& fallback = QString::null)
00058 {
00059 return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16,
00060 fallback );
00061 }
00062
00063 static QString sNamedProp( KTNEFMessage* tnefMsg, const QString& name,
00064 const QString& fallback = QString::null )
00065 {
00066 return tnefMsg->findNamedProp( name, fallback );
00067 }
00068
00069 struct save_tz { char* old_tz; char* tz_env_str; };
00070
00071
00072 static struct save_tz set_tz( const char* _tc )
00073 {
00074 const char *tc = _tc?_tc:"UTC";
00075
00076 struct save_tz rv;
00077
00078 rv.old_tz = 0;
00079 rv.tz_env_str = 0;
00080
00081
00082
00083 char* tz_env = 0;
00084 if( getenv( "TZ" ) ) {
00085 tz_env = strdup( getenv( "TZ" ) );
00086 rv.old_tz = tz_env;
00087 }
00088 char* tmp_env = (char*)malloc( strlen( tc ) + 4 );
00089 strcpy( tmp_env, "TZ=" );
00090 strcpy( tmp_env+3, tc );
00091 putenv( tmp_env );
00092
00093 rv.tz_env_str = tmp_env;
00094
00095
00096
00097 tzset();
00098
00099
00100 return rv;
00101 }
00102
00103
00104 static void unset_tz( struct save_tz old_tz )
00105 {
00106 if( old_tz.old_tz ) {
00107 char* tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 );
00108 strcpy( tmp_env, "TZ=" );
00109 strcpy( tmp_env+3, old_tz.old_tz );
00110 putenv( tmp_env );
00111
00112 free( old_tz.old_tz );
00113 } else {
00114
00115 putenv( strdup("TZ") );
00116 }
00117 tzset();
00118
00119
00120 if( old_tz.tz_env_str ) free( old_tz.tz_env_str );
00121 }
00122
00123 static QDateTime utc2Local( const QDateTime& utcdt )
00124 {
00125 struct tm tmL;
00126
00127 save_tz tmp_tz = set_tz("UTC");
00128 time_t utc = utcdt.toTime_t();
00129 unset_tz( tmp_tz );
00130
00131 localtime_r( &utc, &tmL );
00132 return QDateTime( QDate( tmL.tm_year+1900, tmL.tm_mon+1, tmL.tm_mday ),
00133 QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
00134 }
00135
00136
00137 static QDateTime pureISOToLocalQDateTime( const QString& dtStr,
00138 bool bDateOnly = false )
00139 {
00140 QDate tmpDate;
00141 QTime tmpTime;
00142 int year, month, day, hour, minute, second;
00143
00144 if( bDateOnly ) {
00145 year = dtStr.left( 4 ).toInt();
00146 month = dtStr.mid( 4, 2 ).toInt();
00147 day = dtStr.mid( 6, 2 ).toInt();
00148 hour = 0;
00149 minute = 0;
00150 second = 0;
00151 } else {
00152 year = dtStr.left( 4 ).toInt();
00153 month = dtStr.mid( 4, 2 ).toInt();
00154 day = dtStr.mid( 6, 2 ).toInt();
00155 hour = dtStr.mid( 9, 2 ).toInt();
00156 minute = dtStr.mid( 11, 2 ).toInt();
00157 second = dtStr.mid( 13, 2 ).toInt();
00158 }
00159 tmpDate.setYMD( year, month, day );
00160 tmpTime.setHMS( hour, minute, second );
00161
00162 if( tmpDate.isValid() && tmpTime.isValid() ) {
00163 QDateTime dT = QDateTime( tmpDate, tmpTime );
00164
00165 if( !bDateOnly ) {
00166
00167 if (dtStr.at(dtStr.length()-1) == 'Z') {
00168
00169
00170 dT = utc2Local( dT );
00171 }
00172 }
00173 return dT;
00174 } else
00175 return QDateTime();
00176 }
00177
00178
00179
00180 QString IncidenceFormatter::msTNEFToVPart( const QByteArray& tnef )
00181 {
00182 bool bOk = false;
00183
00184 KTNEFParser parser;
00185 QBuffer buf( tnef );
00186 CalendarLocal cal;
00187 KABC::Addressee addressee;
00188 KABC::VCardConverter cardConv;
00189 ICalFormat calFormat;
00190 Event* event = new Event();
00191
00192 if( parser.openDevice( &buf ) ) {
00193 KTNEFMessage* tnefMsg = parser.message();
00194
00195
00196
00197
00198 QString msgClass = tnefMsg->findProp( 0x001A, QString::null, true )
00199 .upper();
00200 if( !msgClass.isEmpty() ) {
00201
00202
00203 bool bCompatClassAppointment = false;
00204 bool bCompatMethodRequest = false;
00205 bool bCompatMethodCancled = false;
00206 bool bCompatMethodAccepted = false;
00207 bool bCompatMethodAcceptedCond = false;
00208 bool bCompatMethodDeclined = false;
00209 if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ) {
00210 bCompatClassAppointment = true;
00211 if( msgClass.endsWith( ".MTGREQ" ) )
00212 bCompatMethodRequest = true;
00213 if( msgClass.endsWith( ".MTGCNCL" ) )
00214 bCompatMethodCancled = true;
00215 if( msgClass.endsWith( ".MTGRESPP" ) )
00216 bCompatMethodAccepted = true;
00217 if( msgClass.endsWith( ".MTGRESPA" ) )
00218 bCompatMethodAcceptedCond = true;
00219 if( msgClass.endsWith( ".MTGRESPN" ) )
00220 bCompatMethodDeclined = true;
00221 }
00222 bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" );
00223
00224 if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) {
00225
00226 bool bIsReply = false;
00227 QString prodID = "-//Microsoft Corporation//Outlook ";
00228 prodID += tnefMsg->findNamedProp( "0x8554", "9.0" );
00229 prodID += "MIMEDIR/EN\n";
00230 prodID += "VERSION:2.0\n";
00231 calFormat.setApplication( "Outlook", prodID );
00232
00233 Scheduler::Method method;
00234 if( bCompatMethodRequest )
00235 method = Scheduler::Request;
00236 else if( bCompatMethodCancled )
00237 method = Scheduler::Cancel;
00238 else if( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
00239 bCompatMethodDeclined ) {
00240 method = Scheduler::Reply;
00241 bIsReply = true;
00242 } else {
00243
00244
00245
00246
00247
00248
00249
00250
00251 if( tnefMsg->findProp(0x0c17) == "1" )
00252 bIsReply = true;
00253 method = Scheduler::Request;
00254 }
00255
00257 ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown );
00258
00259 QString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) );
00260
00261 if( !sSenderSearchKeyEmail.isEmpty() ) {
00262 int colon = sSenderSearchKeyEmail.find( ':' );
00263
00264 if( sSenderSearchKeyEmail.find( ':' ) == -1 )
00265 sSenderSearchKeyEmail.remove( 0, colon+1 );
00266 }
00267
00268 QString s( tnefMsg->findProp( 0x0e04 ) );
00269 QStringList attendees = QStringList::split( ';', s );
00270 if( attendees.count() ) {
00271 for( QStringList::Iterator it = attendees.begin();
00272 it != attendees.end(); ++it ) {
00273
00274
00275 if( (*it).find('@') == -1 ) {
00276 s = (*it).stripWhiteSpace();
00277
00278 Attendee *attendee = new Attendee( s, s, true );
00279 if( bIsReply ) {
00280 if( bCompatMethodAccepted )
00281 attendee->setStatus( Attendee::Accepted );
00282 if( bCompatMethodDeclined )
00283 attendee->setStatus( Attendee::Declined );
00284 if( bCompatMethodAcceptedCond )
00285 attendee->setStatus(Attendee::Tentative);
00286 } else {
00287 attendee->setStatus( Attendee::NeedsAction );
00288 attendee->setRole( Attendee::ReqParticipant );
00289 }
00290 event->addAttendee(attendee);
00291 }
00292 }
00293 } else {
00294
00295
00296 s = sSenderSearchKeyEmail;
00297 if( !s.isEmpty() ) {
00298 Attendee *attendee = new Attendee( QString::null, QString::null,
00299 true );
00300 if( bIsReply ) {
00301 if( bCompatMethodAccepted )
00302 attendee->setStatus( Attendee::Accepted );
00303 if( bCompatMethodAcceptedCond )
00304 attendee->setStatus( Attendee::Declined );
00305 if( bCompatMethodDeclined )
00306 attendee->setStatus( Attendee::Tentative );
00307 } else {
00308 attendee->setStatus(Attendee::NeedsAction);
00309 attendee->setRole(Attendee::ReqParticipant);
00310 }
00311 event->addAttendee(attendee);
00312 }
00313 }
00314 s = tnefMsg->findProp( 0x0c1f );
00315 if( s.isEmpty() && !bIsReply )
00316 s = sSenderSearchKeyEmail;
00317
00318 if( !s.isEmpty() )
00319 event->setOrganizer( s );
00320
00321 s = tnefMsg->findProp( 0x8516 ).replace( QChar( '-' ), QString::null )
00322 .replace( QChar( ':' ), QString::null );
00323 event->setDtStart( QDateTime::fromString( s ) );
00324
00325 s = tnefMsg->findProp( 0x8517 ).replace( QChar( '-' ), QString::null )
00326 .replace( QChar( ':' ), QString::null );
00327 event->setDtEnd( QDateTime::fromString( s ) );
00328
00329 s = tnefMsg->findProp( 0x8208 );
00330 event->setLocation( s );
00331
00332
00333
00334
00335
00336
00337 s = tnefMsg->findProp( 0x0023 );
00338 event->setUid( s );
00339
00340
00341
00342
00343 s = tnefMsg->findProp( 0x8202 ).replace( QChar( '-' ), QString::null )
00344 .replace( QChar( ':' ), QString::null );
00345
00346
00347
00348 s = tnefMsg->findNamedProp( "Keywords" );
00349 event->setCategories( s );
00350
00351 s = tnefMsg->findProp( 0x1000 );
00352 event->setDescription( s );
00353
00354 s = tnefMsg->findProp( 0x0070 );
00355 event->setSummary( s );
00356
00357 s = tnefMsg->findProp( 0x0026 );
00358 event->setPriority( s.toInt() );
00359
00360
00361 if(!tnefMsg->findProp(0x8503).isEmpty()) {
00362 Alarm *alarm = new Alarm(event);
00363 QDateTime highNoonTime =
00364 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8502 )
00365 .replace( QChar( '-' ), "" )
00366 .replace( QChar( ':' ), "" ) );
00367 QDateTime wakeMeUpTime =
00368 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8560, "" )
00369 .replace( QChar( '-' ), "" )
00370 .replace( QChar( ':' ), "" ) );
00371 alarm->setTime(wakeMeUpTime);
00372
00373 if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
00374 alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
00375 else
00376
00377 alarm->setStartOffset( Duration( 15*60 ) );
00378 alarm->setDisplayAlarm( i18n( "Reminder" ) );
00379
00380
00381
00382 event->addAlarm( alarm );
00383 }
00384 cal.addEvent( event );
00385 bOk = true;
00386
00387 } else if( bCompatClassNote || "IPM.CONTACT" == msgClass ) {
00388 addressee.setUid( stringProp( tnefMsg, attMSGID ) );
00389 addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
00390 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true );
00391 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false );
00392 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false );
00393 addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
00394 addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
00395 addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
00396 addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
00397 addressee.insertCustom( "KADDRESSBOOK", "X-Department", stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
00398 addressee.insertCustom( "KADDRESSBOOK", "X-Office", stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
00399 addressee.insertCustom( "KADDRESSBOOK", "X-Profession", stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
00400
00401 QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY )
00402 .replace( QChar( '-' ), QString::null )
00403 .replace( QChar( ':' ), QString::null );
00404 if( !s.isEmpty() )
00405 addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s );
00406
00407 addressee.setUrl( KURL( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) );
00408
00409
00410 addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
00411 addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
00412 addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
00413 addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
00414 addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
00415
00416 addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
00417 addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
00418 addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
00419
00420
00421
00422
00423
00424 KABC::Address adr;
00425 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
00426 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
00427 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
00428 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
00429 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
00430 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
00431 adr.setType(KABC::Address::Home);
00432 addressee.insertAddress(adr);
00433
00434 adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
00435 adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
00436 adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
00437 adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
00438 adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
00439 adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
00440 adr.setType( KABC::Address::Work );
00441 addressee.insertAddress( adr );
00442
00443 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
00444 adr.setStreet( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
00445 adr.setLocality( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
00446 adr.setRegion( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
00447 adr.setPostalCode( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
00448 adr.setCountry( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
00449 adr.setType( KABC::Address::Dom );
00450 addressee.insertAddress(adr);
00451
00452
00453
00454
00455
00456 QString nr;
00457 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
00458 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) );
00459 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
00460 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) );
00461 nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
00462 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) );
00463 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
00464 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) );
00465 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
00466 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) );
00467
00468 s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY )
00469 .replace( QChar( '-' ), QString::null )
00470 .replace( QChar( ':' ), QString::null );
00471 if( !s.isEmpty() )
00472 addressee.setBirthday( QDateTime::fromString( s ) );
00473
00474 bOk = ( !addressee.isEmpty() );
00475 } else if( "IPM.NOTE" == msgClass ) {
00476
00477 }
00478 }
00479 }
00480
00481
00482 QString iCal = calFormat.toString( &cal );
00483 if( !iCal.isEmpty() )
00484
00485 return iCal;
00486
00487
00488 KABC::VCardConverter converter;
00489 return converter.createVCard( addressee );
00490 }