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/incidence.h>
00026 #include <libkcal/event.h>
00027 #include <libkcal/todo.h>
00028 #include <libkcal/journal.h>
00029 #include <libkcal/calendar.h>
00030 #include <libkcal/calendarlocal.h>
00031 #include <libkcal/icalformat.h>
00032 #include <libkcal/freebusy.h>
00033 #include <libkcal/recurrence.h>
00034
00035 #include <libkdepim/email.h>
00036
00037 #include <ktnef/ktnefparser.h>
00038 #include <ktnef/ktnefmessage.h>
00039 #include <ktnef/ktnefdefs.h>
00040 #include <kabc/phonenumber.h>
00041 #include <kabc/vcardconverter.h>
00042 #include <kabc/stdaddressbook.h>
00043
00044 #include <kapplication.h>
00045
00046
00047 #include <klocale.h>
00048 #include <kiconloader.h>
00049
00050 #include <qbuffer.h>
00051
00052 #include <time.h>
00053
00054
00055 using namespace KCal;
00056
00057 static const struct {
00058 const char* day;
00059 const char* dayPlain;
00060 } daysOfWeek[] = {
00061 { I18N_NOOP("Mondays"), I18N_NOOP("Monday") },
00062 { I18N_NOOP("Tuesdays"), I18N_NOOP("Tuesday") },
00063 { I18N_NOOP("Wednesdays"), I18N_NOOP("Wednesday") },
00064 { I18N_NOOP("Thursdays"), I18N_NOOP("Thursday") },
00065 { I18N_NOOP("Fridays"), I18N_NOOP("Friday") },
00066 { I18N_NOOP("Saturdays"), I18N_NOOP("Saturday") },
00067 { I18N_NOOP("Sundays"), I18N_NOOP("Sunday") },
00068 };
00069
00070 const int sizeOfDaysOfWeek = sizeof(daysOfWeek) / sizeof(*daysOfWeek);
00071
00072 static const struct {
00073 const int dayNo;
00074 const char *date;
00075 } daysOfMonth[] = {
00076 { 1, I18N_NOOP("1st") },
00077 { 2, I18N_NOOP("2nd") },
00078 { 3, I18N_NOOP("3rd") },
00079 { 4, I18N_NOOP("4th") },
00080 { 5, I18N_NOOP("5th") },
00081 { 6, I18N_NOOP("6th") },
00082 { 7, I18N_NOOP("7th") },
00083 { 8, I18N_NOOP("8th") },
00084 { 9, I18N_NOOP("9th") },
00085 { 10, I18N_NOOP("10th") },
00086 { 11, I18N_NOOP("11th") },
00087 { 12, I18N_NOOP("12th") },
00088 { 13, I18N_NOOP("13th") },
00089 { 14, I18N_NOOP("14th") },
00090 { 15, I18N_NOOP("15th") },
00091 { 16, I18N_NOOP("16th") },
00092 { 17, I18N_NOOP("17th") },
00093 { 18, I18N_NOOP("18th") },
00094 { 19, I18N_NOOP("19th") },
00095 { 20, I18N_NOOP("20th") },
00096 { 21, I18N_NOOP("21st") },
00097 { 22, I18N_NOOP("22nd") },
00098 { 23, I18N_NOOP("23rd") },
00099 { 24, I18N_NOOP("24th") },
00100 { 25, I18N_NOOP("25th") },
00101 { 26, I18N_NOOP("26th") },
00102 { 27, I18N_NOOP("27th") },
00103 { 28, I18N_NOOP("28th") },
00104 { 29, I18N_NOOP("29th") },
00105 { 30, I18N_NOOP("30th") },
00106 { 31, I18N_NOOP("31st") },
00107 { -1, I18N_NOOP("last day") },
00108 { -2, I18N_NOOP("2nd last day") },
00109 { -3, I18N_NOOP("3rd last day") },
00110 { -4, I18N_NOOP("4th last day") },
00111 { -5, I18N_NOOP("5th last day") },
00112 };
00113
00114 const int sizeOfDaysOfMonth = sizeof (daysOfMonth) / sizeof (*daysOfMonth);
00115
00116 static const struct {
00117 const char* month;
00118 } monthsOfYear[] = {
00119 { I18N_NOOP("January") },
00120 { I18N_NOOP("February") },
00121 { I18N_NOOP("March") },
00122 { I18N_NOOP("April") },
00123 { I18N_NOOP("May") },
00124 { I18N_NOOP("June") },
00125 { I18N_NOOP("July") },
00126 { I18N_NOOP("August") },
00127 { I18N_NOOP("September") },
00128 { I18N_NOOP("October") },
00129 { I18N_NOOP("November") },
00130 { I18N_NOOP("December") }
00131 };
00132
00133 const int sizeOfMonthsofYear = sizeof(monthsOfYear) / sizeof(*monthsOfYear);
00134
00135
00136 static QString stringProp( KTNEFMessage* tnefMsg, const Q_UINT32& key,
00137 const QString& fallback = QString::null)
00138 {
00139 return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16,
00140 fallback );
00141 }
00142
00143 static QString sNamedProp( KTNEFMessage* tnefMsg, const QString& name,
00144 const QString& fallback = QString::null )
00145 {
00146 return tnefMsg->findNamedProp( name, fallback );
00147 }
00148
00149 struct save_tz { char* old_tz; char* tz_env_str; };
00150
00151
00152 static struct save_tz set_tz( const char* _tc )
00153 {
00154 const char *tc = _tc?_tc:"UTC";
00155
00156 struct save_tz rv;
00157
00158 rv.old_tz = 0;
00159 rv.tz_env_str = 0;
00160
00161
00162
00163 char* tz_env = 0;
00164 if( getenv( "TZ" ) ) {
00165 tz_env = strdup( getenv( "TZ" ) );
00166 rv.old_tz = tz_env;
00167 }
00168 char* tmp_env = (char*)malloc( strlen( tc ) + 4 );
00169 strcpy( tmp_env, "TZ=" );
00170 strcpy( tmp_env+3, tc );
00171 putenv( tmp_env );
00172
00173 rv.tz_env_str = tmp_env;
00174
00175
00176
00177 tzset();
00178
00179
00180 return rv;
00181 }
00182
00183
00184 static void unset_tz( struct save_tz old_tz )
00185 {
00186 if( old_tz.old_tz ) {
00187 char* tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 );
00188 strcpy( tmp_env, "TZ=" );
00189 strcpy( tmp_env+3, old_tz.old_tz );
00190 putenv( tmp_env );
00191
00192 free( old_tz.old_tz );
00193 } else {
00194
00195 putenv( strdup("TZ") );
00196 }
00197 tzset();
00198
00199
00200 if( old_tz.tz_env_str ) free( old_tz.tz_env_str );
00201 }
00202
00203 static QDateTime utc2Local( const QDateTime& utcdt )
00204 {
00205 struct tm tmL;
00206
00207 save_tz tmp_tz = set_tz("UTC");
00208 time_t utc = utcdt.toTime_t();
00209 unset_tz( tmp_tz );
00210
00211 localtime_r( &utc, &tmL );
00212 return QDateTime( QDate( tmL.tm_year+1900, tmL.tm_mon+1, tmL.tm_mday ),
00213 QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
00214 }
00215
00216
00217 static QDateTime pureISOToLocalQDateTime( const QString& dtStr,
00218 bool bDateOnly = false )
00219 {
00220 QDate tmpDate;
00221 QTime tmpTime;
00222 int year, month, day, hour, minute, second;
00223
00224 if( bDateOnly ) {
00225 year = dtStr.left( 4 ).toInt();
00226 month = dtStr.mid( 4, 2 ).toInt();
00227 day = dtStr.mid( 6, 2 ).toInt();
00228 hour = 0;
00229 minute = 0;
00230 second = 0;
00231 } else {
00232 year = dtStr.left( 4 ).toInt();
00233 month = dtStr.mid( 4, 2 ).toInt();
00234 day = dtStr.mid( 6, 2 ).toInt();
00235 hour = dtStr.mid( 9, 2 ).toInt();
00236 minute = dtStr.mid( 11, 2 ).toInt();
00237 second = dtStr.mid( 13, 2 ).toInt();
00238 }
00239 tmpDate.setYMD( year, month, day );
00240 tmpTime.setHMS( hour, minute, second );
00241
00242 if( tmpDate.isValid() && tmpTime.isValid() ) {
00243 QDateTime dT = QDateTime( tmpDate, tmpTime );
00244
00245 if( !bDateOnly ) {
00246
00247 if (dtStr.at(dtStr.length()-1) == 'Z') {
00248
00249
00250 dT = utc2Local( dT );
00251 }
00252 }
00253 return dT;
00254 } else
00255 return QDateTime();
00256 }
00257
00258
00259
00260 QString IncidenceFormatter::msTNEFToVPart( const QByteArray& tnef )
00261 {
00262 bool bOk = false;
00263
00264 KTNEFParser parser;
00265 QBuffer buf( tnef );
00266 CalendarLocal cal;
00267 KABC::Addressee addressee;
00268 KABC::VCardConverter cardConv;
00269 ICalFormat calFormat;
00270 Event* event = new Event();
00271
00272 if( parser.openDevice( &buf ) ) {
00273 KTNEFMessage* tnefMsg = parser.message();
00274
00275
00276
00277
00278 QString msgClass = tnefMsg->findProp( 0x001A, QString::null, true )
00279 .upper();
00280 if( !msgClass.isEmpty() ) {
00281
00282
00283 bool bCompatClassAppointment = false;
00284 bool bCompatMethodRequest = false;
00285 bool bCompatMethodCancled = false;
00286 bool bCompatMethodAccepted = false;
00287 bool bCompatMethodAcceptedCond = false;
00288 bool bCompatMethodDeclined = false;
00289 if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ) {
00290 bCompatClassAppointment = true;
00291 if( msgClass.endsWith( ".MTGREQ" ) )
00292 bCompatMethodRequest = true;
00293 if( msgClass.endsWith( ".MTGCNCL" ) )
00294 bCompatMethodCancled = true;
00295 if( msgClass.endsWith( ".MTGRESPP" ) )
00296 bCompatMethodAccepted = true;
00297 if( msgClass.endsWith( ".MTGRESPA" ) )
00298 bCompatMethodAcceptedCond = true;
00299 if( msgClass.endsWith( ".MTGRESPN" ) )
00300 bCompatMethodDeclined = true;
00301 }
00302 bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" );
00303
00304 if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) {
00305
00306 bool bIsReply = false;
00307 QString prodID = "-//Microsoft Corporation//Outlook ";
00308 prodID += tnefMsg->findNamedProp( "0x8554", "9.0" );
00309 prodID += "MIMEDIR/EN\n";
00310 prodID += "VERSION:2.0\n";
00311 calFormat.setApplication( "Outlook", prodID );
00312
00313 Scheduler::Method method;
00314 if( bCompatMethodRequest )
00315 method = Scheduler::Request;
00316 else if( bCompatMethodCancled )
00317 method = Scheduler::Cancel;
00318 else if( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
00319 bCompatMethodDeclined ) {
00320 method = Scheduler::Reply;
00321 bIsReply = true;
00322 } else {
00323
00324
00325
00326
00327
00328
00329
00330
00331 if( tnefMsg->findProp(0x0c17) == "1" )
00332 bIsReply = true;
00333 method = Scheduler::Request;
00334 }
00335
00337 ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown );
00338
00339 QString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) );
00340
00341 if( !sSenderSearchKeyEmail.isEmpty() ) {
00342 int colon = sSenderSearchKeyEmail.find( ':' );
00343
00344 if( sSenderSearchKeyEmail.find( ':' ) == -1 )
00345 sSenderSearchKeyEmail.remove( 0, colon+1 );
00346 }
00347
00348 QString s( tnefMsg->findProp( 0x0e04 ) );
00349 QStringList attendees = QStringList::split( ';', s );
00350 if( attendees.count() ) {
00351 for( QStringList::Iterator it = attendees.begin();
00352 it != attendees.end(); ++it ) {
00353
00354
00355 if( (*it).find('@') == -1 ) {
00356 s = (*it).stripWhiteSpace();
00357
00358 Attendee *attendee = new Attendee( s, s, true );
00359 if( bIsReply ) {
00360 if( bCompatMethodAccepted )
00361 attendee->setStatus( Attendee::Accepted );
00362 if( bCompatMethodDeclined )
00363 attendee->setStatus( Attendee::Declined );
00364 if( bCompatMethodAcceptedCond )
00365 attendee->setStatus(Attendee::Tentative);
00366 } else {
00367 attendee->setStatus( Attendee::NeedsAction );
00368 attendee->setRole( Attendee::ReqParticipant );
00369 }
00370 event->addAttendee(attendee);
00371 }
00372 }
00373 } else {
00374
00375
00376 s = sSenderSearchKeyEmail;
00377 if( !s.isEmpty() ) {
00378 Attendee *attendee = new Attendee( QString::null, QString::null,
00379 true );
00380 if( bIsReply ) {
00381 if( bCompatMethodAccepted )
00382 attendee->setStatus( Attendee::Accepted );
00383 if( bCompatMethodAcceptedCond )
00384 attendee->setStatus( Attendee::Declined );
00385 if( bCompatMethodDeclined )
00386 attendee->setStatus( Attendee::Tentative );
00387 } else {
00388 attendee->setStatus(Attendee::NeedsAction);
00389 attendee->setRole(Attendee::ReqParticipant);
00390 }
00391 event->addAttendee(attendee);
00392 }
00393 }
00394 s = tnefMsg->findProp( 0x0c1f );
00395 if( s.isEmpty() && !bIsReply )
00396 s = sSenderSearchKeyEmail;
00397
00398 if( !s.isEmpty() )
00399 event->setOrganizer( s );
00400
00401 s = tnefMsg->findProp( 0x8516 ).replace( QChar( '-' ), QString::null )
00402 .replace( QChar( ':' ), QString::null );
00403 event->setDtStart( QDateTime::fromString( s ) );
00404
00405 s = tnefMsg->findProp( 0x8517 ).replace( QChar( '-' ), QString::null )
00406 .replace( QChar( ':' ), QString::null );
00407 event->setDtEnd( QDateTime::fromString( s ) );
00408
00409 s = tnefMsg->findProp( 0x8208 );
00410 event->setLocation( s );
00411
00412
00413
00414
00415
00416
00417 s = tnefMsg->findProp( 0x0023 );
00418 event->setUid( s );
00419
00420
00421
00422
00423 s = tnefMsg->findProp( 0x8202 ).replace( QChar( '-' ), QString::null )
00424 .replace( QChar( ':' ), QString::null );
00425
00426
00427
00428 s = tnefMsg->findNamedProp( "Keywords" );
00429 event->setCategories( s );
00430
00431 s = tnefMsg->findProp( 0x1000 );
00432 event->setDescription( s );
00433
00434 s = tnefMsg->findProp( 0x0070 );
00435 event->setSummary( s );
00436
00437 s = tnefMsg->findProp( 0x0026 );
00438 event->setPriority( s.toInt() );
00439
00440
00441 if(!tnefMsg->findProp(0x8503).isEmpty()) {
00442 Alarm *alarm = new Alarm(event);
00443 QDateTime highNoonTime =
00444 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8502 )
00445 .replace( QChar( '-' ), "" )
00446 .replace( QChar( ':' ), "" ) );
00447 QDateTime wakeMeUpTime =
00448 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8560, "" )
00449 .replace( QChar( '-' ), "" )
00450 .replace( QChar( ':' ), "" ) );
00451 alarm->setTime(wakeMeUpTime);
00452
00453 if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
00454 alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
00455 else
00456
00457 alarm->setStartOffset( Duration( 15*60 ) );
00458 alarm->setDisplayAlarm( i18n( "Reminder" ) );
00459
00460
00461
00462 event->addAlarm( alarm );
00463 }
00464 cal.addEvent( event );
00465 bOk = true;
00466
00467 } else if( bCompatClassNote || "IPM.CONTACT" == msgClass ) {
00468 addressee.setUid( stringProp( tnefMsg, attMSGID ) );
00469 addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
00470 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true );
00471 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false );
00472 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false );
00473 addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
00474 addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
00475 addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
00476 addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
00477 addressee.insertCustom( "KADDRESSBOOK", "X-Department", stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
00478 addressee.insertCustom( "KADDRESSBOOK", "X-Office", stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
00479 addressee.insertCustom( "KADDRESSBOOK", "X-Profession", stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
00480
00481 QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY )
00482 .replace( QChar( '-' ), QString::null )
00483 .replace( QChar( ':' ), QString::null );
00484 if( !s.isEmpty() )
00485 addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s );
00486
00487 addressee.setUrl( KURL( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) );
00488
00489
00490 addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
00491 addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
00492 addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
00493 addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
00494 addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
00495
00496 addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
00497 addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
00498 addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
00499
00500
00501
00502
00503
00504 KABC::Address adr;
00505 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
00506 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
00507 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
00508 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
00509 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
00510 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
00511 adr.setType(KABC::Address::Home);
00512 addressee.insertAddress(adr);
00513
00514 adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
00515 adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
00516 adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
00517 adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
00518 adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
00519 adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
00520 adr.setType( KABC::Address::Work );
00521 addressee.insertAddress( adr );
00522
00523 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
00524 adr.setStreet( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
00525 adr.setLocality( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
00526 adr.setRegion( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
00527 adr.setPostalCode( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
00528 adr.setCountry( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
00529 adr.setType( KABC::Address::Dom );
00530 addressee.insertAddress(adr);
00531
00532
00533
00534
00535
00536 QString nr;
00537 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
00538 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) );
00539 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
00540 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) );
00541 nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
00542 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) );
00543 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
00544 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) );
00545 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
00546 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) );
00547
00548 s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY )
00549 .replace( QChar( '-' ), QString::null )
00550 .replace( QChar( ':' ), QString::null );
00551 if( !s.isEmpty() )
00552 addressee.setBirthday( QDateTime::fromString( s ) );
00553
00554 bOk = ( !addressee.isEmpty() );
00555 } else if( "IPM.NOTE" == msgClass ) {
00556
00557 }
00558 }
00559 }
00560
00561
00562 QString iCal = calFormat.toString( &cal );
00563 if( !iCal.isEmpty() )
00564
00565 return iCal;
00566
00567
00568 KABC::VCardConverter converter;
00569 return converter.createVCard( addressee );
00570 }
00571
00572 static QString weeklyRecurrenceAsString( Recurrence * recur )
00573 {
00574 Q_ASSERT( recur->doesRecur() == Recurrence::rWeekly );
00575
00576
00577
00578
00579 QStringList dayList;
00580 for ( int i = 0; i < sizeOfDaysOfWeek; i++ ) {
00581 if( recur->days().testBit(i) ) {
00582 dayList+= i18n( daysOfWeek[i].day );
00583 }
00584 }
00585
00586 QString strDays;
00587 if( dayList.count() > 1 ) {
00588 strDays = dayList.join(", ");
00589 strDays.replace( strDays.findRev(','), 1, i18n(" and") );
00590 } else if( dayList.count() == 1 ) {
00591 strDays = dayList.first();
00592 }
00593 return strDays;
00594 }
00595
00596 static QString monthlyPosRecurrenceAsString( Recurrence * recur )
00597 {
00598 Q_ASSERT( recur->doesRecur() == Recurrence::rMonthlyPos );
00599
00600 QString strDays;
00601
00602 Recurrence::rMonthPos *tmpDay;
00603
00604
00605
00606
00607
00608
00609
00610
00611 QPtrList<Recurrence::rMonthPos> tmpDays = recur->monthPositions();
00612 for ( tmpDay = tmpDays.first();
00613 tmpDay;
00614 tmpDay = tmpDays.next() ) {
00615
00616 QString day;
00617 for ( int i = 0; i < sizeOfDaysOfWeek; i++ ) {
00618 if( tmpDay->rDays.testBit(i) ) {
00619 day = i18n( daysOfWeek[i].dayPlain );
00620 break;
00621 }
00622 }
00623 strDays += i18n( "%1 %2").arg( i18n( daysOfMonth[ tmpDay->rPos - 1 ].date ) ).arg( day );
00624 }
00625
00626 return strDays;
00627 }
00628
00629 static QString monthlyDayRecurrenceAsString( Recurrence * recur )
00630 {
00631 Q_ASSERT( recur->doesRecur() == Recurrence::rMonthlyDay );
00632
00633 QString strDays;
00634
00635 int *tmpDay;
00636 QPtrList<int> tmpDays = recur->monthDays();
00637 for ( tmpDay = tmpDays.first();
00638 tmpDay;
00639 tmpDay = tmpDays.next() ) {
00640 strDays += i18n( daysOfMonth[ *tmpDay - 1 ].date ) + " ";
00641 }
00642
00643 return strDays;
00644 }
00645
00646
00647
00648
00649
00650 static QString yearlyMonthRecurrenceAsString( Recurrence * recur )
00651 {
00652 Q_ASSERT( recur->doesRecur() == Recurrence::rYearlyMonth );
00653
00654 QString strDays;
00655 QPtrList<int> days = recur->monthDays();
00656 int *day = days.first();
00657 int *tmpMonth;
00658 QPtrList<int> tmpMonths = recur->yearNums();
00659 for ( tmpMonth = tmpMonths.first();
00660 tmpMonth;
00661 tmpMonth = tmpMonths.next()) {
00662 strDays = i18n( "%1 day of %2" ).arg( i18n( daysOfMonth[ *day - 1 ].date ) )
00663 .arg( i18n( monthsOfYear[ *tmpMonth - 1 ].month ) );
00664 }
00665 return strDays;
00666 }
00667
00668
00669
00670 static QString yearlyDayRecurrenceAsString( Recurrence * recur )
00671 {
00672 Q_ASSERT( recur->doesRecur() == Recurrence::rYearlyDay );
00673
00674 int *tmpDay;
00675 QString strDays;
00676 QPtrList<int> tmpDays = recur->yearNums();
00677 tmpDay = tmpDays.first();
00678 strDays += i18n( "%1 ").arg( *tmpDay );
00679
00680 return strDays;
00681 }
00682
00683
00684 static QString yearlyPosRecurrenceAsString( Recurrence * recur )
00685 {
00686 Q_ASSERT( recur->doesRecur() == Recurrence::rYearlyPos );
00687
00688 int *tmpMonth;
00689 QString strDays;
00690 QString day;
00691
00692 QPtrList<Recurrence::rMonthPos> tmpDays = recur->yearMonthPositions();
00693 Recurrence::rMonthPos *tmpDay = tmpDays.first();
00694 for ( int i = 0; i < sizeOfDaysOfWeek; i++ ) {
00695 if( tmpDay->rDays.testBit(i) ) {
00696 day = i18n( daysOfWeek[i].dayPlain );
00697 break;
00698 }
00699 }
00700
00701 QPtrList<int> tmpMonths = recur->yearNums();
00702 tmpMonth = tmpMonths.first();
00703 strDays += i18n("%1 %2 of %3 ").arg( i18n( daysOfMonth[ tmpDay->rPos - 1 ].date ) )
00704 .arg( day )
00705 .arg( i18n( monthsOfYear[ *tmpMonth - 1 ].month ) );
00706 return strDays;
00707 }
00708
00709 QString IncidenceFormatter::recurrenceAsHTML( Incidence * incidence )
00710 {
00711 QString result;
00712
00713 if ( incidence->doesRecur() ) {
00714 Recurrence *recur = incidence->recurrence();
00715 switch (recur->doesRecur())
00716 {
00717 case Recurrence::rDaily:
00718 result += i18n("Recurs every day. ", "Recurs every %n days.",recur->frequency());
00719 break;
00720 case Recurrence::rWeekly:
00721 result += i18n("Recurs every week on %1. ", "Recurs every %n weeks on %1.",recur->frequency())
00722 .arg( weeklyRecurrenceAsString( recur ) );
00723 break;
00724 case Recurrence::rMonthlyPos:
00725 result += i18n("Recurs on the %1 of every month.", "Recurs on the %1 every %n months.", recur->frequency())
00726 .arg( monthlyPosRecurrenceAsString( recur ) );
00727 break;
00728 case Recurrence::rMonthlyDay:
00729 result += i18n("Recurs on the %1 of every month.", "Recurs on the %1 every %n months.", recur->frequency())
00730 .arg( monthlyDayRecurrenceAsString( recur ) );
00731 break;
00732 case Recurrence::rYearlyMonth:
00733 result += i18n("Recurs on the %1 of every year.", "Recurs on %1 every %n years.", recur->frequency())
00734 .arg( yearlyMonthRecurrenceAsString( recur ) );
00735 break;
00736 case Recurrence::rYearlyDay:
00737 result += i18n("Recurs on day %1 of every year.", "Recurs on %1 day every %n years.", recur->frequency())
00738 .arg( yearlyDayRecurrenceAsString( recur ) );
00739 break;
00740 case Recurrence::rYearlyPos:
00741 result += i18n("Recurs on the %1 of every year.", "Recurs on %1 every %n years.", recur->frequency())
00742 .arg( yearlyPosRecurrenceAsString( recur ) );
00743 break;
00744 }
00745
00746 if ( recur->duration() > 0 ) {
00747 result += i18n (" Repeats once.", " Repeats %n times.", recur->duration());
00748 result += '\n';
00749 } else {
00750 if ( recur->duration() != -1 ) {
00751
00752 QString endstr;
00753 if ( incidence->doesFloat() ) {
00754 endstr = KGlobal::locale()->formatDate( recur->endDate() );
00755 } else {
00756 endstr = KGlobal::locale()->formatDateTime( recur->endDateTime() );
00757 }
00758 result += i18n(" Repeats until: %1.<br>").arg( endstr );
00759 } else {
00760 result += i18n(" Repeats forever.<br>");
00761 }
00762 }
00763 const DateList exdates = incidence->exDates();
00764 if ( !exdates.isEmpty() )
00765 result += i18n("Except: ");
00766 DateList::ConstIterator it( exdates.begin() );
00767 while ( it != exdates.end() ) {
00768 if ( it != exdates.begin() )
00769 result += " ,";
00770 QDate d(*it++);
00771 result += KGlobal::locale()->formatDateTime( d );
00772 }
00773 if ( !exdates.isEmpty() )
00774 result += "<br>";
00775
00776 }
00777 return result;
00778 }
00779
00780