00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "incidenceformatter.h"
00024
00025 #include <libkcal/attachment.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/calendarresources.h>
00034
00035 #include <libemailfunctions/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 #include <kemailsettings.h>
00046
00047
00048 #include <klocale.h>
00049 #include <kglobal.h>
00050 #include <kiconloader.h>
00051 #include <kcalendarsystem.h>
00052
00053 #include <qbuffer.h>
00054 #include <qstylesheet.h>
00055 #include <qdatetime.h>
00056
00057 #include <time.h>
00058
00059
00060 using namespace KCal;
00061
00062
00063
00064
00065
00066
00067 static QString eventViewerAddLink( const QString &ref, const QString &text,
00068 bool newline = true )
00069 {
00070 QString tmpStr( "<a href=\"" + ref + "\">" + text + "</a>" );
00071 if ( newline ) tmpStr += "\n";
00072 return tmpStr;
00073 }
00074
00075 static QString eventViewerAddTag( const QString & tag, const QString & text )
00076 {
00077 int numLineBreaks = text.contains( "\n" );
00078 QString str = "<" + tag + ">";
00079 QString tmpText = text;
00080 QString tmpStr = str;
00081 if( numLineBreaks >= 0 ) {
00082 if ( numLineBreaks > 0) {
00083 int pos = 0;
00084 QString tmp;
00085 for( int i = 0; i <= numLineBreaks; i++ ) {
00086 pos = tmpText.find( "\n" );
00087 tmp = tmpText.left( pos );
00088 tmpText = tmpText.right( tmpText.length() - pos - 1 );
00089 tmpStr += tmp + "<br>";
00090 }
00091 } else {
00092 tmpStr += tmpText;
00093 }
00094 }
00095 tmpStr += "</" + tag + ">";
00096 return tmpStr;
00097 }
00098
00099 static QString linkPerson( const QString& email, QString name, QString uid )
00100 {
00101
00102
00103 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
00104 KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
00105 KABC::Addressee::List addressList = add_book->findByEmail( email );
00106 KABC::Addressee o = addressList.first();
00107 if ( !o.isEmpty() && addressList.size() < 2 ) {
00108 if ( name.isEmpty() )
00109
00110 name = o.formattedName();
00111 uid = o.uid();
00112 } else
00113
00114 uid = QString::null;
00115 }
00116 kdDebug(5850) << "formatAttendees: uid = " << uid << endl;
00117
00118
00119 QString tmpString = "<li>";
00120 if ( !uid.isEmpty() ) {
00121
00122 if ( name.isEmpty() )
00123
00124 tmpString += eventViewerAddLink( "uid:" + uid, email );
00125 else
00126 tmpString += eventViewerAddLink( "uid:" + uid, name );
00127 } else {
00128
00129 tmpString += ( name.isEmpty() ? email : name );
00130 }
00131 tmpString += '\n';
00132
00133
00134 if ( !email.isEmpty() ) {
00135 KCal::Person person( name, email );
00136 KURL mailto;
00137 mailto.setProtocol( "mailto" );
00138 mailto.setPath( person.fullName() );
00139 tmpString += eventViewerAddLink( mailto.url(), QString::null );
00140 }
00141 tmpString += "</li>\n";
00142
00143 return tmpString;
00144 }
00145
00146 static QString eventViewerFormatAttendees( Incidence *event )
00147 {
00148 QString tmpStr;
00149 Attendee::List attendees = event->attendees();
00150 if ( attendees.count() ) {
00151
00152
00153 tmpStr += eventViewerAddTag( "i", i18n("Organizer") );
00154 tmpStr += "<ul>";
00155 tmpStr += linkPerson( event->organizer().email(),
00156 event->organizer().name(), QString::null );
00157 tmpStr += "</ul>";
00158
00159
00160 tmpStr += eventViewerAddTag( "i", i18n("Attendees") );
00161 tmpStr += "<ul>";
00162 Attendee::List::ConstIterator it;
00163 for( it = attendees.begin(); it != attendees.end(); ++it ) {
00164 Attendee *a = *it;
00165 tmpStr += linkPerson( a->email(), a->name(), a->uid() );
00166 if ( !a->delegator().isEmpty() ) {
00167 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
00168 }
00169 if ( !a->delegate().isEmpty() ) {
00170 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
00171 }
00172 }
00173 tmpStr += "</ul>";
00174 }
00175 return tmpStr;
00176 }
00177
00178 static QString eventViewerFormatAttachments( Incidence *i )
00179 {
00180 QString tmpStr;
00181 Attachment::List as = i->attachments();
00182 if ( as.count() > 0 ) {
00183 Attachment::List::ConstIterator it;
00184 for( it = as.begin(); it != as.end(); ++it ) {
00185 if ( (*it)->isUri() ) {
00186 QString name;
00187 if ( (*it)->uri().startsWith( "kmail:" ) )
00188 name = i18n( "Show mail" );
00189 else
00190 name = (*it)->uri();
00191 tmpStr += eventViewerAddLink( (*it)->uri(), name );
00192 tmpStr += "<br>";
00193 }
00194 }
00195 }
00196 return tmpStr;
00197 }
00198
00199
00200
00201
00202
00203 static QString eventViewerFormatBirthday( Event *event )
00204 {
00205 if ( !event) return QString::null;
00206 if ( event->customProperty("KABC","BIRTHDAY") != "YES" ) return QString::null;
00207
00208 QString uid = event->customProperty("KABC","UID-1");
00209 QString name = event->customProperty("KABC","NAME-1");
00210 QString email= event->customProperty("KABC","EMAIL-1");
00211
00212 QString tmpString = "<ul>";
00213 tmpString += linkPerson( email, name, uid );
00214
00215 if ( event->customProperty( "KABC", "ANNIVERSARY") == "YES" ) {
00216 uid = event->customProperty("KABC","UID-2");
00217 name = event->customProperty("KABC","NAME-2");
00218 email= event->customProperty("KABC","EMAIL-2");
00219 tmpString += linkPerson( email, name, uid );
00220 }
00221
00222 tmpString += "</ul>";
00223 return tmpString;
00224 }
00225
00226 static QString eventViewerFormatHeader( Incidence *incidence )
00227 {
00228 QString tmpStr = "<table><tr>";
00229
00230
00231 {
00232 tmpStr += "<td>";
00233
00234 if ( incidence->type() == "Event" ) {
00235 tmpStr += "<img src=\"" +
00236 KGlobal::iconLoader()->iconPath( "appointment", KIcon::Small ) +
00237 "\">";
00238 }
00239 if ( incidence->type() == "Todo" ) {
00240 tmpStr += "<img src=\"" +
00241 KGlobal::iconLoader()->iconPath( "todo", KIcon::Small ) +
00242 "\">";
00243 }
00244 if ( incidence->type() == "Journal" ) {
00245 tmpStr += "<img src=\"" +
00246 KGlobal::iconLoader()->iconPath( "journal", KIcon::Small ) +
00247 "\">";
00248 }
00249 if ( incidence->isAlarmEnabled() ) {
00250 tmpStr += "<img src=\"" +
00251 KGlobal::iconLoader()->iconPath( "bell", KIcon::Small ) +
00252 "\">";
00253 }
00254 if ( incidence->doesRecur() ) {
00255 tmpStr += "<img src=\"" +
00256 KGlobal::iconLoader()->iconPath( "recur", KIcon::Small ) +
00257 "\">";
00258 }
00259 if ( incidence->isReadOnly() ) {
00260 tmpStr += "<img src=\"" +
00261 KGlobal::iconLoader()->iconPath( "readonlyevent", KIcon::Small ) +
00262 "\">";
00263 }
00264
00265 tmpStr += "</td>";
00266 }
00267
00268 tmpStr += "<td>"
00269 + eventViewerAddTag( "u",
00270 eventViewerAddTag( "b", incidence->summary() ) )
00271 + "</td>";
00272 tmpStr += "</tr></table><br>";
00273
00274 return tmpStr;
00275 }
00276
00277 static QString eventViewerFormatEvent( Event *event )
00278 {
00279 if ( !event ) return QString::null;
00280 QString tmpStr = eventViewerFormatHeader( event );
00281
00282 tmpStr += "<table>";
00283
00284 tmpStr += "<tr>";
00285 if ( event->doesFloat() ) {
00286 if ( event->isMultiDay() ) {
00287 tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
00288 tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
00289 .arg( event->dtStartDateStr() )
00290 .arg( event->dtEndDateStr() ) + "</td>";
00291 } else {
00292 tmpStr += "<td align=\"right\"><b>" + i18n( "Date" ) + "</b></td>";
00293 tmpStr += "<td>" + i18n("date as string","%1").arg( event->dtStartDateStr() ) + "</td>";
00294 }
00295 } else {
00296 if ( event->isMultiDay() ) {
00297 tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
00298 tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
00299 .arg( event->dtStartStr() )
00300 .arg( event->dtEndStr() ) + "</td>";
00301 } else {
00302 tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
00303 if ( event->hasEndDate() && event->dtStart() != event->dtEnd()) {
00304 tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
00305 .arg( event->dtStartTimeStr() )
00306 .arg( event->dtEndTimeStr() ) + "</td>";
00307 } else {
00308 tmpStr += "<td>" + event->dtStartTimeStr() + "</td>";
00309 }
00310 tmpStr += "</tr><tr>";
00311 tmpStr += "<td align=\"right\"><b>" + i18n( "Date" ) + "</b></td>";
00312 tmpStr += "<td>" + i18n("date as string","%1")
00313 .arg( event->dtStartDateStr() ) + "</td>";
00314 }
00315 }
00316 tmpStr += "</tr>";
00317
00318 if ( event->customProperty("KABC","BIRTHDAY")== "YES" ) {
00319 tmpStr += "<tr>";
00320 tmpStr += "<td align=\"right\"><b>" + i18n( "Birthday" ) + "</b></td>";
00321 tmpStr += "<td>" + eventViewerFormatBirthday( event ) + "</td>";
00322 tmpStr += "</tr>";
00323 tmpStr += "</table>";
00324 return tmpStr;
00325 }
00326
00327 if ( !event->description().isEmpty() ) {
00328 tmpStr += "<tr>";
00329 tmpStr += "<td align=\"right\"><b>" + i18n( "Description" ) + "</b></td>";
00330 tmpStr += "<td>" + eventViewerAddTag( "p", event->description() ) + "</td>";
00331 tmpStr += "</tr>";
00332 }
00333
00334 if ( !event->location().isEmpty() ) {
00335 tmpStr += "<tr>";
00336 tmpStr += "<td align=\"right\"><b>" + i18n( "Location" ) + "</b></td>";
00337 tmpStr += "<td>" + event->location() + "</td>";
00338 tmpStr += "</tr>";
00339 }
00340
00341 if ( event->categories().count() > 0 ) {
00342 tmpStr += "<tr>";
00343 tmpStr += "<td align=\"right\"><b>" + i18n( "1 Category", "%n Categories", event->categories().count() )+ "</b></td>";
00344 tmpStr += "<td>" + event->categoriesStr() + "</td>";
00345 tmpStr += "</tr>";
00346 }
00347
00348 if ( event->doesRecur() ) {
00349 QDateTime dt =
00350 event->recurrence()->getNextDateTime( QDateTime::currentDateTime() );
00351 tmpStr += "<tr>";
00352 tmpStr += "<td align=\"right\"><b>" + i18n( "Next on" ) + "</b></td>";
00353 if ( !event->doesFloat() ) {
00354 tmpStr += "<td>" +
00355 KGlobal::locale()->formatDateTime( dt, true ) + "</td>";
00356 } else {
00357 tmpStr += "<td>" +
00358 KGlobal::locale()->formatDate( dt.date(), true ) + "</td>";
00359 }
00360 tmpStr += "</tr>";
00361 }
00362
00363 int attendeeCount = event->attendees().count();
00364 if ( attendeeCount > 0 ) {
00365 tmpStr += "<tr><td colspan=\"2\">";
00366 tmpStr += eventViewerFormatAttendees( event );
00367 tmpStr += "</td></tr>";
00368 }
00369
00370 int attachmentCount = event->attachments().count();
00371 if ( attachmentCount > 0 ) {
00372 tmpStr += "<tr>";
00373 tmpStr += "<td align=\"right\"><b>" + i18n( "1 attachment", "%n attachments", attachmentCount )+ "</b></td>";
00374 tmpStr += "<td>" + eventViewerFormatAttachments( event ) + "</td>";
00375 tmpStr += "</tr>";
00376 }
00377
00378 tmpStr += "</table>";
00379 tmpStr += "<em>" + i18n( "Creation date: %1.").arg(
00380 KGlobal::locale()->formatDateTime( event->created() , true ) ) + "</em>";
00381 return tmpStr;
00382 }
00383
00384 static QString eventViewerFormatTodo( Todo *todo )
00385 {
00386 if ( !todo ) return QString::null;
00387 QString tmpStr = eventViewerFormatHeader( todo );
00388
00389 tmpStr += "<table>";
00390
00391 if ( todo->hasDueDate() ) {
00392 tmpStr += "<tr>";
00393 tmpStr += "<td align=\"right\"><b>" + i18n( "Due on" ) + "</b></td>";
00394 if ( !todo->doesFloat() ) {
00395 tmpStr += "<td>" +
00396 KGlobal::locale()->formatDateTime( todo->dtDue(), true ) +
00397 "</td>";
00398 } else {
00399 tmpStr += "<td>" +
00400 KGlobal::locale()->formatDate( todo->dtDue().date(), true ) +
00401 "</td>";
00402 }
00403 tmpStr += "</tr>";
00404 }
00405
00406 if ( !todo->description().isEmpty() ) {
00407 tmpStr += "<tr>";
00408 tmpStr += "<td align=\"right\"><b>" + i18n( "Description" ) + "</b></td>";
00409 tmpStr += "<td>" + todo->description() + "</td>";
00410 tmpStr += "</tr>";
00411 }
00412
00413 if ( !todo->location().isEmpty() ) {
00414 tmpStr += "<tr>";
00415 tmpStr += "<td align=\"right\"><b>" + i18n( "Location" ) + "</b></td>";
00416 tmpStr += "<td>" + todo->location() + "</td>";
00417 tmpStr += "</tr>";
00418 }
00419
00420 if ( todo->categories().count() > 0 ) {
00421 tmpStr += "<tr>";
00422 tmpStr += "<td align=\"right\"><b>" + i18n( "1 Category", "%n Categories", todo->categories().count() )+ "</b></td>";
00423 tmpStr += "<td>" + todo->categoriesStr() + "</td>";
00424 tmpStr += "</tr>";
00425 }
00426
00427 tmpStr += "<tr>";
00428 tmpStr += "<td align=\"right\"><b>" + i18n( "Priority" ) + "</b></td>";
00429 if ( todo->priority() > 0 ) {
00430 tmpStr += "<td>" + QString::number( todo->priority() ) + "</td>";
00431 } else {
00432 tmpStr += "<td>" + i18n( "Unspecified" ) + "</td>";
00433 }
00434 tmpStr += "</tr>";
00435
00436 tmpStr += "<tr>";
00437 tmpStr += "<td align=\"right\"><b>" + i18n( "Completed" ) + "</b></td>";
00438 tmpStr += "<td>" + i18n( "%1 %" ).arg( todo->percentComplete() ) + "</td>";
00439 tmpStr += "</tr>";
00440
00441 if ( todo->doesRecur() ) {
00442 QDateTime dt =
00443 todo->recurrence()->getNextDateTime( QDateTime::currentDateTime() );
00444 tmpStr += "<tr>";
00445 tmpStr += "<td align=\"right\"><b>" + i18n( "Next on" ) + "</b></td>";
00446 if ( !todo->doesFloat() ) {
00447 tmpStr += "<td>" +
00448 KGlobal::locale()->formatDateTime( dt, true ) + "</td>";
00449 } else {
00450 tmpStr += "<td>" +
00451 KGlobal::locale()->formatDate( dt.date(), true ) + "</td>";
00452 }
00453 tmpStr += "</tr>";
00454 }
00455
00456 int attendeeCount = todo->attendees().count();
00457 if ( attendeeCount > 0 ) {
00458 tmpStr += "<tr><td colspan=\"2\">";
00459 tmpStr += eventViewerFormatAttendees( todo );
00460 tmpStr += "</td></tr>";
00461 }
00462
00463 int attachmentCount = todo->attachments().count();
00464 if ( attachmentCount > 0 ) {
00465 tmpStr += "<tr>";
00466 tmpStr += "<td align=\"right\"><b>" + i18n( "1 attachment", "%n attachments", attachmentCount )+ "</b></td>";
00467 tmpStr += "<td>" + eventViewerFormatAttachments( todo ) + "</td>";
00468 tmpStr += "</tr>";
00469 }
00470
00471 tmpStr += "</table>";
00472 tmpStr += "<em>" + i18n( "Creation date: %1.").arg(
00473 KGlobal::locale()->formatDateTime( todo->created(), true ) ) + "</em>";
00474 return tmpStr;
00475 }
00476
00477 static QString eventViewerFormatJournal( Journal *journal )
00478 {
00479 if ( !journal ) return QString::null;
00480
00481 QString tmpStr;
00482 if ( !journal->summary().isEmpty() ) {
00483 tmpStr += eventViewerAddTag( "u",
00484 eventViewerAddTag( "b", journal->summary() ) );
00485 }
00486 tmpStr += eventViewerAddTag( "b", i18n("Journal for %1").arg( journal->dtStartDateStr( false ) ) );
00487 if ( !journal->description().isEmpty() )
00488 tmpStr += eventViewerAddTag( "p", journal->description() );
00489 return tmpStr;
00490 }
00491
00492 static QString eventViewerFormatFreeBusy( FreeBusy *fb )
00493 {
00494 if ( !fb ) return QString::null;
00495
00496 QString tmpStr =
00497 eventViewerAddTag( "u",
00498 eventViewerAddTag( "b", i18n("Free/Busy information for %1")
00499 .arg( fb->organizer().fullName() ) ) );
00500 tmpStr += eventViewerAddTag( "i", i18n("Busy times in date range %1 - %2:")
00501 .arg( KGlobal::locale()->formatDate( fb->dtStart().date(), true ) )
00502 .arg( KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) ) );
00503
00504 QValueList<Period> periods = fb->busyPeriods();
00505
00506 QString text = eventViewerAddTag( "em", eventViewerAddTag( "b", i18n("Busy:") ) );
00507 QValueList<Period>::iterator it;
00508 for ( it = periods.begin(); it != periods.end(); ++it ) {
00509 Period per = *it;
00510 if ( per.hasDuration() ) {
00511 int dur = per.duration().asSeconds();
00512 QString cont;
00513 if ( dur >= 3600 ) {
00514 cont += i18n("1 hour ", "%n hours ", dur / 3600 );
00515 dur %= 3600;
00516 }
00517 if ( dur >= 60 ) {
00518 cont += i18n("1 minute ", "%n minutes ", dur / 60);
00519 dur %= 60;
00520 }
00521 if ( dur > 0 ) {
00522 cont += i18n("1 second", "%n seconds", dur);
00523 }
00524 text += i18n("startDate for duration", "%1 for %2")
00525 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00526 .arg( cont );
00527 text += "<br>";
00528 } else {
00529 if ( per.start().date() == per.end().date() ) {
00530 text += i18n("date, fromTime - toTime ", "%1, %2 - %3")
00531 .arg( KGlobal::locale()->formatDate( per.start().date() ) )
00532 .arg( KGlobal::locale()->formatTime( per.start().time() ) )
00533 .arg( KGlobal::locale()->formatTime( per.end().time() ) );
00534 } else {
00535 text += i18n("fromDateTime - toDateTime", "%1 - %2")
00536 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00537 .arg( KGlobal::locale()->formatDateTime( per.end(), false ) );
00538 }
00539 text += "<br>";
00540 }
00541 }
00542 tmpStr += eventViewerAddTag( "p", text );
00543 return tmpStr;
00544 }
00545
00546 class IncidenceFormatter::EventViewerVisitor : public IncidenceBase::Visitor
00547 {
00548 public:
00549 EventViewerVisitor() { mResult = ""; }
00550 bool act( IncidenceBase *incidence ) { return incidence->accept( *this ); }
00551 QString result() const { return mResult; }
00552 protected:
00553 bool visit( Event *event )
00554 {
00555 mResult = eventViewerFormatEvent( event );
00556 return !mResult.isEmpty();
00557 }
00558 bool visit( Todo *todo )
00559 {
00560 mResult = eventViewerFormatTodo( todo );
00561 return !mResult.isEmpty();
00562 }
00563 bool visit( Journal *journal )
00564 {
00565 mResult = eventViewerFormatJournal( journal );
00566 return !mResult.isEmpty();
00567 }
00568 bool visit( FreeBusy *fb )
00569 {
00570 mResult = eventViewerFormatFreeBusy( fb );
00571 return !mResult.isEmpty();
00572 }
00573
00574 protected:
00575 QString mResult;
00576 };
00577
00578 QString IncidenceFormatter::extensiveDisplayString( IncidenceBase *incidence )
00579 {
00580 if ( !incidence ) return QString::null;
00581 EventViewerVisitor v;
00582 if ( v.act( incidence ) ) {
00583 return v.result();
00584 } else
00585 return QString::null;
00586 }
00587
00588
00589
00590
00591
00592
00593
00594
00595 static QString string2HTML( const QString& str )
00596 {
00597 return QStyleSheet::escape( str );
00598 }
00599
00600 static QString eventStartTimeStr( Event *event )
00601 {
00602 QString tmp;
00603 if ( !event->doesFloat() ) {
00604 tmp = i18n( "%1: Start Date, %2: Start Time", "%1 %2" ).
00605 arg( event->dtStartDateStr( false ), event->dtStartTimeStr() );
00606 } else {
00607 tmp = i18n( "%1: Start Date", "%1" ).
00608 arg( event->dtStartDateStr( false ) );
00609 }
00610 return tmp;
00611 }
00612
00613 static QString eventEndTimeStr( Event *event )
00614 {
00615 QString tmp;
00616 if ( event->hasEndDate() && event->dtEnd().isValid() ) {
00617 if ( !event->doesFloat() ) {
00618 tmp = i18n( "%1: End Date, %2: End Time", "%1 %2" ).
00619 arg( event->dtEndDateStr( false ), event->dtEndTimeStr() );
00620 } else {
00621 tmp = i18n( "%1: End Date", "%1" ).arg( event->dtEndDateStr( false ) );
00622 }
00623 }
00624 return tmp;
00625 }
00626
00627 static QString invitationRow( const QString &cell1, const QString &cell2 )
00628 {
00629 return "<tr><td>" + cell1 + "</td><td>" + cell2 + "</td></tr>\n";
00630 }
00631
00632 static bool iamOrganizer( Incidence *incidence )
00633 {
00634
00635
00636 if ( !incidence ) {
00637 return false;
00638 }
00639
00640 bool iam = false;
00641 KEMailSettings settings;
00642 QStringList profiles = settings.profiles();
00643 for( QStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
00644 settings.setProfile( *it );
00645 if ( settings.getSetting( KEMailSettings::EmailAddress ) == incidence->organizer().email() ) {
00646 iam = true;
00647 break;
00648 }
00649 }
00650 return iam;
00651 }
00652
00653 static bool iamAttendee( Attendee *attendee )
00654 {
00655
00656
00657 bool iam = false;
00658 KEMailSettings settings;
00659 QStringList profiles = settings.profiles();
00660 for( QStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
00661 settings.setProfile( *it );
00662 if ( settings.getSetting( KEMailSettings::EmailAddress ) == attendee->email() ) {
00663 iam = true;
00664 break;
00665 }
00666 }
00667 return iam;
00668 }
00669
00670 static Attendee *findMyAttendee( Incidence *incidence )
00671 {
00672
00673
00674 Attendee *attendee = 0;
00675 if ( !incidence ) {
00676 return attendee;
00677 }
00678
00679 KEMailSettings settings;
00680 QStringList profiles = settings.profiles();
00681 for( QStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
00682 settings.setProfile( *it );
00683
00684 Attendee::List attendees = incidence->attendees();
00685 Attendee::List::ConstIterator it2;
00686 for ( it2 = attendees.begin(); it2 != attendees.end(); ++it2 ) {
00687 Attendee *a = *it2;
00688 if ( settings.getSetting( KEMailSettings::EmailAddress ) == a->email() ) {
00689 attendee = a;
00690 break;
00691 }
00692 }
00693 }
00694 return attendee;
00695 }
00696
00697 static Attendee *findAttendee( Incidence *incidence, const QString &email )
00698 {
00699
00700
00701 Attendee *attendee = 0;
00702 if ( !incidence ) {
00703 return attendee;
00704 }
00705
00706 Attendee::List attendees = incidence->attendees();
00707 Attendee::List::ConstIterator it;
00708 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00709 Attendee *a = *it;
00710 if ( email == a->email() ) {
00711 attendee = a;
00712 break;
00713 }
00714 }
00715 return attendee;
00716 }
00717
00718 static bool rsvpRequested( Incidence *incidence )
00719 {
00720
00721
00722 bool rsvp = true;
00723 Attendee::List attendees = incidence->attendees();
00724 Attendee::List::ConstIterator it;
00725 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00726 if ( it == attendees.begin() ) {
00727 rsvp = (*it)->RSVP();
00728 } else {
00729 if ( (*it)->RSVP() != rsvp ) {
00730 rsvp = true;
00731 break;
00732 }
00733 }
00734 }
00735 return rsvp;
00736 }
00737
00738 static QString rsvpRequestedStr( bool rsvpRequested )
00739 {
00740 if ( rsvpRequested ) {
00741 return i18n( "Your response is requested" );
00742 } else {
00743 return i18n( "A response is not necessary" );
00744 }
00745 }
00746
00747 static QString invitationPerson( const QString& email, QString name, QString uid )
00748 {
00749
00750
00751 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
00752 KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
00753 KABC::Addressee::List addressList = add_book->findByEmail( email );
00754 KABC::Addressee o = addressList.first();
00755 if ( !o.isEmpty() && addressList.size() < 2 ) {
00756 if ( name.isEmpty() )
00757
00758 name = o.formattedName();
00759 uid = o.uid();
00760 } else
00761
00762 uid = QString::null;
00763 }
00764
00765
00766 QString tmpString;
00767 if ( !uid.isEmpty() ) {
00768
00769 if ( name.isEmpty() )
00770
00771 tmpString += eventViewerAddLink( "uid:" + uid, email );
00772 else
00773 tmpString += eventViewerAddLink( "uid:" + uid, name );
00774 } else {
00775
00776 tmpString += ( name.isEmpty() ? email : name );
00777 }
00778 tmpString += '\n';
00779
00780
00781 if ( !email.isEmpty() ) {
00782 KCal::Person person( name, email );
00783 KURL mailto;
00784 mailto.setProtocol( "mailto" );
00785 mailto.setPath( person.fullName() );
00786 tmpString += eventViewerAddLink( mailto.url(), QString::null );
00787 }
00788 tmpString += "\n";
00789
00790 return tmpString;
00791 }
00792
00793 static QString invitationsDetailsIncidence( Incidence *incidence )
00794 {
00795 QString html;
00796 QString descr;
00797 QStringList comments;
00798 if ( incidence->comments().isEmpty() && !incidence->description().isEmpty() ) {
00799 comments << incidence->description();
00800 } else {
00801 descr = incidence->description();
00802 comments = incidence->comments();
00803 }
00804
00805 if( !descr.isEmpty() ) {
00806 html += "<br/><u>" + i18n("Description:")
00807 + "</u><table border=\"0\"><tr><td> </td><td>";
00808 html += string2HTML(descr) + "</td></tr></table>";
00809 }
00810 if ( !comments.isEmpty() ) {
00811 html += "<br><u>" + i18n("Comments:")
00812 + "</u><table border=\"0\"><tr><td> </td><td>";
00813 if ( comments.count() > 1 ) {
00814 html += "<ul>";
00815 for ( uint i = 0; i < comments.count(); ++i )
00816 html += "<li>" + string2HTML( comments[i] ) + "</li>";
00817 html += "</ul>";
00818 } else {
00819 html += string2HTML( comments[0] );
00820 }
00821 html += "</td></tr></table>";
00822 }
00823 return html;
00824 }
00825
00826 static QString invitationDetailsEvent( Event* event )
00827 {
00828
00829 if ( !event )
00830 return QString::null;
00831
00832 QString html;
00833 QString tmp;
00834
00835 QString sSummary = i18n( "Summary unspecified" );
00836 if ( ! event->summary().isEmpty() ) {
00837 sSummary = string2HTML( event->summary() );
00838 }
00839
00840 QString sLocation = i18n( "Location unspecified" );
00841 if ( ! event->location().isEmpty() ) {
00842 sLocation = string2HTML( event->location() );
00843 }
00844
00845 QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00846 html = QString("<div dir=\"%1\">\n").arg(dir);
00847
00848 html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
00849
00850
00851 html += invitationRow( i18n( "What:" ), sSummary );
00852 html += invitationRow( i18n( "Where:" ), sLocation );
00853
00854
00855 if ( event->dtStart().date() == event->dtEnd().date() ) {
00856 html += invitationRow( i18n( "Date:" ), event->dtStartDateStr( false ) );
00857 if ( !event->doesFloat() ) {
00858 html += invitationRow( i18n( "Time:" ),
00859 event->dtStartTimeStr() + " - " + event->dtEndTimeStr() );
00860 }
00861 } else {
00862 html += invitationRow( i18n( "Starting date of an event", "From:" ), event->dtStartDateStr( false ) );
00863 if ( !event->doesFloat() ) {
00864 html += invitationRow( i18n( "Starting time of an event", "At:" ), event->dtStartTimeStr() );
00865 }
00866 if ( event->hasEndDate() ) {
00867 html += invitationRow( i18n( "Ending date of an event", "To:" ), event->dtEndDateStr( false ) );
00868 if ( !event->doesFloat() ) {
00869 html += invitationRow( i18n( "Starting time of an event", "At:" ), event->dtEndTimeStr() );
00870 }
00871 } else {
00872 html += invitationRow( i18n( "Ending date of an event", "To:" ), i18n( "no end date specified" ) );
00873 }
00874 }
00875
00876
00877 if ( !event->doesFloat() && event->hasEndDate() ) {
00878 tmp = QString::null;
00879 QTime sDuration(0,0,0), t;
00880 int secs = event->dtStart().secsTo( event->dtEnd() );
00881 t = sDuration.addSecs( secs );
00882 if ( t.hour() > 0 ) {
00883 tmp += i18n( "1 hour ", "%n hours ", t.hour() );
00884 }
00885 if ( t.minute() > 0 ) {
00886 tmp += i18n( "1 minute ", "%n minutes ", t.minute() );
00887 }
00888
00889 html += invitationRow( i18n( "Duration:" ), tmp );
00890 }
00891
00892 if ( event->doesRecur() )
00893 html += invitationRow( i18n( "Recurrence:" ), IncidenceFormatter::recurrenceString( event ) );
00894
00895 html += "</table>\n";
00896 html += invitationsDetailsIncidence( event );
00897 html += "</div>\n";
00898
00899 return html;
00900 }
00901
00902 static QString invitationDetailsTodo( Todo *todo )
00903 {
00904
00905 if ( !todo )
00906 return QString::null;
00907
00908 QString sSummary = i18n( "Summary unspecified" );
00909 QString sDescr = i18n( "Description unspecified" );
00910 if ( ! todo->summary().isEmpty() ) {
00911 sSummary = todo->summary();
00912 }
00913 if ( ! todo->description().isEmpty() ) {
00914 sDescr = todo->description();
00915 }
00916 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00917 html += invitationRow( i18n( "Summary:" ), sSummary );
00918 html += invitationRow( i18n( "Description:" ), sDescr );
00919 html += "</table>\n";
00920 html += invitationsDetailsIncidence( todo );
00921
00922 return html;
00923 }
00924
00925 static QString invitationDetailsJournal( Journal *journal )
00926 {
00927 if ( !journal )
00928 return QString::null;
00929
00930 QString sSummary = i18n( "Summary unspecified" );
00931 QString sDescr = i18n( "Description unspecified" );
00932 if ( ! journal->summary().isEmpty() ) {
00933 sSummary = journal->summary();
00934 }
00935 if ( ! journal->description().isEmpty() ) {
00936 sDescr = journal->description();
00937 }
00938 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00939 html += invitationRow( i18n( "Summary:" ), sSummary );
00940 html += invitationRow( i18n( "Date:" ), journal->dtStartDateStr( false ) );
00941 html += invitationRow( i18n( "Description:" ), sDescr );
00942 html += "</table>\n";
00943 html += invitationsDetailsIncidence( journal );
00944
00945 return html;
00946 }
00947
00948 static QString invitationDetailsFreeBusy( FreeBusy *fb )
00949 {
00950 if ( !fb )
00951 return QString::null;
00952 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00953
00954 html += invitationRow( i18n("Person:"), fb->organizer().fullName() );
00955 html += invitationRow( i18n("Start date:"), fb->dtStartDateStr() );
00956 html += invitationRow( i18n("End date:"),
00957 KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) );
00958 html += "<tr><td colspan=2><hr></td></tr>\n";
00959 html += "<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n";
00960
00961 QValueList<Period> periods = fb->busyPeriods();
00962
00963 QValueList<Period>::iterator it;
00964 for ( it = periods.begin(); it != periods.end(); ++it ) {
00965 Period per = *it;
00966 if ( per.hasDuration() ) {
00967 int dur = per.duration().asSeconds();
00968 QString cont;
00969 if ( dur >= 3600 ) {
00970 cont += i18n("1 hour ", "%n hours ", dur / 3600);
00971 dur %= 3600;
00972 }
00973 if ( dur >= 60 ) {
00974 cont += i18n("1 minute", "%n minutes ", dur / 60);
00975 dur %= 60;
00976 }
00977 if ( dur > 0 ) {
00978 cont += i18n("1 second", "%n seconds", dur);
00979 }
00980 html += invitationRow( QString::null, i18n("startDate for duration", "%1 for %2")
00981 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00982 .arg(cont) );
00983 } else {
00984 QString cont;
00985 if ( per.start().date() == per.end().date() ) {
00986 cont = i18n("date, fromTime - toTime ", "%1, %2 - %3")
00987 .arg( KGlobal::locale()->formatDate( per.start().date() ) )
00988 .arg( KGlobal::locale()->formatTime( per.start().time() ) )
00989 .arg( KGlobal::locale()->formatTime( per.end().time() ) );
00990 } else {
00991 cont = i18n("fromDateTime - toDateTime", "%1 - %2")
00992 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00993 .arg( KGlobal::locale()->formatDateTime( per.end(), false ) );
00994 }
00995
00996 html += invitationRow( QString::null, cont );
00997 }
00998 }
00999
01000 html += "</table>\n";
01001 return html;
01002 }
01003
01004 static QString invitationHeaderEvent( Event *event, ScheduleMessage *msg )
01005 {
01006 if ( !msg || !event )
01007 return QString::null;
01008
01009 switch ( msg->method() ) {
01010 case Scheduler::Publish:
01011 return i18n( "This event has been published" );
01012 case Scheduler::Request:
01013 if ( event->revision() > 0 ) {
01014 return i18n( "This invitation has been updated" );
01015 }
01016 if ( iamOrganizer( event ) ) {
01017 return i18n( "I sent this invitation" );
01018 } else {
01019 if ( !event->organizer().fullName().isEmpty() ) {
01020 return i18n( "You received an invitation from %1" ).
01021 arg( event->organizer().fullName() );
01022 } else {
01023 return i18n( "You received an invitation" );
01024 }
01025 }
01026 case Scheduler::Refresh:
01027 return i18n( "This invitation was refreshed" );
01028 case Scheduler::Cancel:
01029 return i18n( "This invitation has been canceled" );
01030 case Scheduler::Add:
01031 return i18n( "Addition to the invitation" );
01032 case Scheduler::Reply: {
01033 Attendee::List attendees = event->attendees();
01034 if( attendees.count() == 0 ) {
01035 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
01036 return QString::null;
01037 }
01038 if( attendees.count() != 1 ) {
01039 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
01040 << "but is " << attendees.count() << endl;
01041 }
01042 Attendee* attendee = *attendees.begin();
01043 QString attendeeName = attendee->name();
01044 if ( attendeeName.isEmpty() ) {
01045 attendeeName = attendee->email();
01046 }
01047 if ( attendeeName.isEmpty() ) {
01048 attendeeName = i18n( "Sender" );
01049 }
01050
01051 QString delegatorName, dummy;
01052 KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
01053 if ( delegatorName.isEmpty() ) {
01054 delegatorName = attendee->delegator();
01055 }
01056
01057 switch( attendee->status() ) {
01058 case Attendee::NeedsAction:
01059 return i18n( "%1 indicates this invitation still needs some action" ).arg( attendeeName );
01060 case Attendee::Accepted:
01061 if ( delegatorName.isEmpty() ) {
01062 return i18n( "%1 accepts this invitation" ).arg( attendeeName );
01063 } else {
01064 return i18n( "%1 accepts this invitation on behalf of %2" ).
01065 arg( attendeeName ).arg( delegatorName );
01066 }
01067 case Attendee::Tentative:
01068 if ( delegatorName.isEmpty() ) {
01069 return i18n( "%1 tentatively accepts this invitation" ).
01070 arg( attendeeName );
01071 } else {
01072 return i18n( "%1 tentatively accepts this invitation on behalf of %2" ).
01073 arg( attendeeName ).arg( delegatorName );
01074 }
01075 case Attendee::Declined:
01076 if ( delegatorName.isEmpty() ) {
01077 return i18n( "%1 declines this invitation" ).arg( attendeeName );
01078 } else {
01079 return i18n( "%1 declines this invitation on behalf of %2" ).
01080 arg( attendeeName ).arg( delegatorName );
01081 }
01082 case Attendee::Delegated: {
01083 QString delegate, dummy;
01084 KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
01085 if ( delegate.isEmpty() ) {
01086 delegate = attendee->delegate();
01087 }
01088 if ( !delegate.isEmpty() ) {
01089 return i18n( "%1 has delegated this invitation to %2" ).
01090 arg( attendeeName ) .arg( delegate );
01091 } else {
01092 return i18n( "%1 has delegated this invitation" ).arg( attendeeName );
01093 }
01094 }
01095 case Attendee::Completed:
01096 return i18n( "This invitation is now completed" );
01097 case Attendee::InProcess:
01098 return i18n( "%1 is still processing the invitation" ).
01099 arg( attendeeName );
01100 default:
01101 return i18n( "Unknown response to this invitation" );
01102 }
01103 break; }
01104 case Scheduler::Counter:
01105 return i18n( "Sender makes this counter proposal" );
01106 case Scheduler::Declinecounter:
01107 return i18n( "Sender declines the counter proposal" );
01108 case Scheduler::NoMethod:
01109 return i18n("Error: iMIP message with unknown method: '%1'").
01110 arg( msg->method() );
01111 }
01112 return QString::null;
01113 }
01114
01115 static QString invitationHeaderTodo( Todo *todo, ScheduleMessage *msg )
01116 {
01117 if ( !msg || !todo ) {
01118 return QString::null;
01119 }
01120
01121 switch ( msg->method() ) {
01122 case Scheduler::Publish:
01123 return i18n("This task has been published");
01124 case Scheduler::Request:
01125 if ( todo->revision() > 0 ) {
01126 return i18n( "This task has been updated" );
01127 } else {
01128 return i18n( "You have been assigned this task" );
01129 }
01130 case Scheduler::Refresh:
01131 return i18n( "This task was refreshed" );
01132 case Scheduler::Cancel:
01133 return i18n( "This task was canceled" );
01134 case Scheduler::Add:
01135 return i18n( "Addition to the task" );
01136 case Scheduler::Reply: {
01137 Attendee::List attendees = todo->attendees();
01138 if( attendees.count() == 0 ) {
01139 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
01140 return QString::null;
01141 }
01142 if( attendees.count() != 1 ) {
01143 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
01144 << "but is " << attendees.count() << endl;
01145 }
01146 Attendee* attendee = *attendees.begin();
01147
01148 switch( attendee->status() ) {
01149 case Attendee::NeedsAction:
01150 return i18n( "Sender indicates this task assignment still needs some action" );
01151 case Attendee::Accepted:
01152 return i18n( "Sender accepts this task" );
01153 case Attendee::Tentative:
01154 return i18n( "Sender tentatively accepts this task" );
01155 case Attendee::Declined:
01156 return i18n( "Sender declines this task" );
01157 case Attendee::Delegated: {
01158 QString delegate, dummy;
01159 KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
01160 if ( delegate.isEmpty() ) {
01161 delegate = attendee->delegate();
01162 }
01163 if ( !delegate.isEmpty() ) {
01164 return i18n( "Sender has delegated this request for the task to %1" ).arg( delegate );
01165 } else {
01166 return i18n( "Sender has delegated this request for the task " );
01167 }
01168 }
01169 case Attendee::Completed:
01170 return i18n( "The request for this task is now completed" );
01171 case Attendee::InProcess:
01172 return i18n( "Sender is still processing the invitation" );
01173 default:
01174 return i18n( "Unknown response to this task" );
01175 }
01176 break; }
01177 case Scheduler::Counter:
01178 return i18n( "Sender makes this counter proposal" );
01179 case Scheduler::Declinecounter:
01180 return i18n( "Sender declines the counter proposal" );
01181 case Scheduler::NoMethod:
01182 return i18n("Error: iMIP message with unknown method: '%1'").
01183 arg( msg->method() );
01184 }
01185 return QString::null;
01186 }
01187
01188 static QString invitationHeaderJournal( Journal *journal, ScheduleMessage *msg )
01189 {
01190
01191 if ( !msg || !journal ) {
01192 return QString::null;
01193 }
01194
01195 switch ( msg->method() ) {
01196 case Scheduler::Publish:
01197 return i18n("This journal has been published");
01198 case Scheduler::Request:
01199 return i18n( "You have been assigned this journal" );
01200 case Scheduler::Refresh:
01201 return i18n( "This journal was refreshed" );
01202 case Scheduler::Cancel:
01203 return i18n( "This journal was canceled" );
01204 case Scheduler::Add:
01205 return i18n( "Addition to the journal" );
01206 case Scheduler::Reply: {
01207 Attendee::List attendees = journal->attendees();
01208 if( attendees.count() == 0 ) {
01209 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
01210 return QString::null;
01211 }
01212 if( attendees.count() != 1 ) {
01213 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
01214 << "but is " << attendees.count() << endl;
01215 }
01216 Attendee* attendee = *attendees.begin();
01217
01218 switch( attendee->status() ) {
01219 case Attendee::NeedsAction:
01220 return i18n( "Sender indicates this journal assignment still needs some action" );
01221 case Attendee::Accepted:
01222 return i18n( "Sender accepts this journal" );
01223 case Attendee::Tentative:
01224 return i18n( "Sender tentatively accepts this journal" );
01225 case Attendee::Declined:
01226 return i18n( "Sender declines this journal" );
01227 case Attendee::Delegated:
01228 return i18n( "Sender has delegated this request for the journal" );
01229 case Attendee::Completed:
01230 return i18n( "The request for this journal is now completed" );
01231 case Attendee::InProcess:
01232 return i18n( "Sender is still processing the invitation" );
01233 default:
01234 return i18n( "Unknown response to this journal" );
01235 }
01236 break;
01237 }
01238 case Scheduler::Counter:
01239 return i18n( "Sender makes this counter proposal" );
01240 case Scheduler::Declinecounter:
01241 return i18n( "Sender declines the counter proposal" );
01242 case Scheduler::NoMethod:
01243 return i18n("Error: iMIP message with unknown method: '%1'").
01244 arg( msg->method() );
01245 }
01246 return QString::null;
01247 }
01248
01249 static QString invitationHeaderFreeBusy( FreeBusy *fb, ScheduleMessage *msg )
01250 {
01251 if ( !msg || !fb ) {
01252 return QString::null;
01253 }
01254
01255 switch ( msg->method() ) {
01256 case Scheduler::Publish:
01257 return i18n("This free/busy list has been published");
01258 case Scheduler::Request:
01259 return i18n( "The free/busy list has been requested" );
01260 case Scheduler::Refresh:
01261 return i18n( "This free/busy list was refreshed" );
01262 case Scheduler::Cancel:
01263 return i18n( "This free/busy list was canceled" );
01264 case Scheduler::Add:
01265 return i18n( "Addition to the free/busy list" );
01266 case Scheduler::NoMethod:
01267 default:
01268 return i18n("Error: Free/Busy iMIP message with unknown method: '%1'").
01269 arg( msg->method() );
01270 }
01271 }
01272
01273 static QString invitationAttendees( Incidence *incidence )
01274 {
01275 QString tmpStr;
01276 if ( !incidence ) {
01277 return tmpStr;
01278 }
01279
01280 tmpStr += eventViewerAddTag( "u", i18n( "Attendee List" ) );
01281 tmpStr += "<br/>";
01282
01283 int count=0;
01284 Attendee::List attendees = incidence->attendees();
01285 if ( !attendees.isEmpty() ) {
01286
01287 Attendee::List::ConstIterator it;
01288 for( it = attendees.begin(); it != attendees.end(); ++it ) {
01289 Attendee *a = *it;
01290 if ( !iamAttendee( a ) ) {
01291 count++;
01292 if ( count == 1 ) {
01293 tmpStr += "<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\" columns=\"2\">";
01294 }
01295 tmpStr += "<tr>";
01296 tmpStr += "<td>";
01297 tmpStr += invitationPerson( a->email(), a->name(), QString::null );
01298 if ( !a->delegator().isEmpty() ) {
01299 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
01300 }
01301 if ( !a->delegate().isEmpty() ) {
01302 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
01303 }
01304 tmpStr += "</td>";
01305 tmpStr += "<td>" + a->statusStr() + "</td>";
01306 tmpStr += "</tr>";
01307 }
01308 }
01309 }
01310 if ( count ) {
01311 tmpStr += "</table>";
01312 } else {
01313 tmpStr += "<i>" + i18n( "No attendee", "None" ) + "</i>";
01314 }
01315
01316 return tmpStr;
01317 }
01318
01319 class IncidenceFormatter::ScheduleMessageVisitor : public IncidenceBase::Visitor
01320 {
01321 public:
01322 ScheduleMessageVisitor() : mMessage(0) { mResult = ""; }
01323 bool act( IncidenceBase *incidence, ScheduleMessage *msg ) { mMessage = msg; return incidence->accept( *this ); }
01324 QString result() const { return mResult; }
01325
01326 protected:
01327 QString mResult;
01328 ScheduleMessage *mMessage;
01329 };
01330
01331 class IncidenceFormatter::InvitationHeaderVisitor :
01332 public IncidenceFormatter::ScheduleMessageVisitor
01333 {
01334 protected:
01335 bool visit( Event *event )
01336 {
01337 mResult = invitationHeaderEvent( event, mMessage );
01338 return !mResult.isEmpty();
01339 }
01340 bool visit( Todo *todo )
01341 {
01342 mResult = invitationHeaderTodo( todo, mMessage );
01343 return !mResult.isEmpty();
01344 }
01345 bool visit( Journal *journal )
01346 {
01347 mResult = invitationHeaderJournal( journal, mMessage );
01348 return !mResult.isEmpty();
01349 }
01350 bool visit( FreeBusy *fb )
01351 {
01352 mResult = invitationHeaderFreeBusy( fb, mMessage );
01353 return !mResult.isEmpty();
01354 }
01355 };
01356
01357 class IncidenceFormatter::InvitationBodyVisitor :
01358 public IncidenceFormatter::ScheduleMessageVisitor
01359 {
01360 protected:
01361 bool visit( Event *event )
01362 {
01363 mResult = invitationDetailsEvent( event );
01364 return !mResult.isEmpty();
01365 }
01366 bool visit( Todo *todo )
01367 {
01368 mResult = invitationDetailsTodo( todo );
01369 return !mResult.isEmpty();
01370 }
01371 bool visit( Journal *journal )
01372 {
01373 mResult = invitationDetailsJournal( journal );
01374 return !mResult.isEmpty();
01375 }
01376 bool visit( FreeBusy *fb )
01377 {
01378 mResult = invitationDetailsFreeBusy( fb );
01379 return !mResult.isEmpty();
01380 }
01381 };
01382
01383 class IncidenceFormatter::IncidenceCompareVisitor :
01384 public IncidenceBase::Visitor
01385 {
01386 public:
01387 IncidenceCompareVisitor() : mExistingIncidence(0) {}
01388 bool act( IncidenceBase *incidence, Incidence* existingIncidence )
01389 {
01390 Incidence *inc = dynamic_cast<Incidence*>( incidence );
01391 if ( !inc || !existingIncidence || inc->revision() <= existingIncidence->revision() )
01392 return false;
01393 mExistingIncidence = existingIncidence;
01394 return incidence->accept( *this );
01395 }
01396
01397 QString result() const
01398 {
01399 if ( mChanges.isEmpty() )
01400 return QString();
01401 QString html = "<div align=\"left\"><ul><li>";
01402 html += mChanges.join( "</li><li>" );
01403 html += "</li><ul></div>";
01404 return html;
01405 }
01406
01407 protected:
01408 bool visit( Event *event )
01409 {
01410 compareEvents( event, dynamic_cast<Event*>( mExistingIncidence ) );
01411 compareIncidences( event, mExistingIncidence );
01412 return !mChanges.isEmpty();
01413 }
01414 bool visit( Todo *todo )
01415 {
01416 compareIncidences( todo, mExistingIncidence );
01417 return !mChanges.isEmpty();
01418 }
01419 bool visit( Journal *journal )
01420 {
01421 compareIncidences( journal, mExistingIncidence );
01422 return !mChanges.isEmpty();
01423 }
01424 bool visit( FreeBusy *fb )
01425 {
01426 Q_UNUSED( fb );
01427 return !mChanges.isEmpty();
01428 }
01429
01430 private:
01431 void compareEvents( Event *newEvent, Event *oldEvent )
01432 {
01433 if ( !oldEvent || !newEvent )
01434 return;
01435 if ( oldEvent->dtStart() != newEvent->dtStart() || oldEvent->doesFloat() != newEvent->doesFloat() )
01436 mChanges += i18n( "The invitation starting time has been changed from %1 to %2" )
01437 .arg( eventStartTimeStr( oldEvent ) ).arg( eventStartTimeStr( newEvent ) );
01438 if ( oldEvent->dtEnd() != newEvent->dtEnd() || oldEvent->doesFloat() != newEvent->doesFloat() )
01439 mChanges += i18n( "The invitation ending time has been changed from %1 to %2" )
01440 .arg( eventEndTimeStr( oldEvent ) ).arg( eventEndTimeStr( newEvent ) );
01441 }
01442
01443 void compareIncidences( Incidence *newInc, Incidence *oldInc )
01444 {
01445 if ( !oldInc || !newInc )
01446 return;
01447 if ( oldInc->summary() != newInc->summary() )
01448 mChanges += i18n( "The summary has been changed to: \"%1\"" ).arg( newInc->summary() );
01449 if ( oldInc->location() != newInc->location() )
01450 mChanges += i18n( "The location has been changed to: \"%1\"" ).arg( newInc->location() );
01451 if ( oldInc->description() != newInc->description() )
01452 mChanges += i18n( "The description has been changed to: \"%1\"" ).arg( newInc->description() );
01453 Attendee::List oldAttendees = oldInc->attendees();
01454 Attendee::List newAttendees = newInc->attendees();
01455 for ( Attendee::List::ConstIterator it = newAttendees.constBegin(); it != newAttendees.constEnd(); ++it ) {
01456 Attendee *oldAtt = oldInc->attendeeByMail( (*it)->email() );
01457 if ( !oldAtt ) {
01458 mChanges += i18n( "Attendee %1 has been added" ).arg( (*it)->fullName() );
01459 } else {
01460 if ( oldAtt->status() != (*it)->status() )
01461 mChanges += i18n( "The status of attendee %1 has been changed to: %2" ).arg( (*it)->fullName() )
01462 .arg( (*it)->statusStr() );
01463 }
01464 }
01465 for ( Attendee::List::ConstIterator it = oldAttendees.constBegin(); it != oldAttendees.constEnd(); ++it ) {
01466 Attendee *newAtt = newInc->attendeeByMail( (*it)->email() );
01467 if ( !newAtt )
01468 mChanges += i18n( "Attendee %1 has been removed" ).arg( (*it)->fullName() );
01469 }
01470 }
01471
01472 private:
01473 Incidence* mExistingIncidence;
01474 QStringList mChanges;
01475 };
01476
01477
01478 QString InvitationFormatterHelper::makeLink( const QString &id, const QString &text )
01479 {
01480 QString res( "<a href=\"%1\"><b>%2</b></a>" );
01481 return res.arg( generateLinkURL( id ) ).arg( text );
01482 return res;
01483 }
01484
01485 QString IncidenceFormatter::formatICalInvitation( QString invitation, Calendar *mCalendar,
01486 InvitationFormatterHelper *helper )
01487 {
01488 if ( invitation.isEmpty() ) return QString::null;
01489
01490 ICalFormat format;
01491
01492 ScheduleMessage *msg = format.parseScheduleMessage( mCalendar, invitation );
01493
01494 if( !msg ) {
01495 kdDebug( 5850 ) << "Failed to parse the scheduling message" << endl;
01496 Q_ASSERT( format.exception() );
01497 kdDebug( 5850 ) << format.exception()->message() << endl;
01498 return QString::null;
01499 }
01500
01501 IncidenceBase *incBase = msg->event();
01502
01503
01504 Incidence *existingIncidence = 0;
01505 if ( incBase && helper->calendar() ) {
01506 existingIncidence = helper->calendar()->incidence( incBase->uid() );
01507 if ( !existingIncidence ) {
01508 const Incidence::List list = helper->calendar()->incidences();
01509 for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
01510 if ( (*it)->schedulingID() == incBase->uid() ) {
01511 existingIncidence = *it;
01512 break;
01513 }
01514 }
01515 }
01516 }
01517
01518
01519 QString html;
01520
01521 QString tableStyle = QString::fromLatin1(
01522 "style=\"border: solid 1px; margin: 0em;\"" );
01523 QString tableHead = QString::fromLatin1(
01524 "<div align=\"center\">"
01525 "<table width=\"80%\" cellpadding=\"1\" cellspacing=\"0\" %1>"
01526 "<tr><td>").arg(tableStyle);
01527
01528 html += tableHead;
01529 InvitationHeaderVisitor headerVisitor;
01530
01531 if ( !headerVisitor.act( incBase, msg ) )
01532 return QString::null;
01533 html += "<b>" + headerVisitor.result() + "</b>";
01534
01535 InvitationBodyVisitor bodyVisitor;
01536 if ( !bodyVisitor.act( incBase, msg ) )
01537 return QString::null;
01538 html += bodyVisitor.result();
01539
01540 if ( msg->method() == Scheduler::Request ) {
01541 IncidenceCompareVisitor compareVisitor;
01542 if ( compareVisitor.act( incBase, existingIncidence ) ) {
01543 html += i18n("<p align=\"left\">The following changes have been made by the organizer:</p>");
01544 html += compareVisitor.result();
01545 }
01546 }
01547
01548 Incidence *inc = dynamic_cast<Incidence*>( incBase );
01549
01550
01551 bool myInc = iamOrganizer( inc );
01552
01553
01554 bool rsvpRec = false;
01555 Attendee *ea = 0;
01556 if ( !myInc ) {
01557 if ( existingIncidence ) {
01558 ea = findMyAttendee( existingIncidence );
01559 }
01560 if ( ea && ( ea->status() == Attendee::Accepted || ea->status() == Attendee::Declined ) ) {
01561 rsvpRec = true;
01562 }
01563 }
01564
01565
01566 bool rsvpReq = rsvpRequested( inc );
01567 if ( !myInc ) {
01568 html += "<br/>";
01569 html += "<i><u>";
01570 if ( rsvpRec && ( inc && inc->revision() == 0 ) ) {
01571 html += i18n( "Your response has already been recorded [%1]" ).
01572 arg( ea->statusStr() );
01573 rsvpReq = false;
01574 } else {
01575 html += rsvpRequestedStr( rsvpReq );
01576 }
01577 html += "</u></i><br>";
01578 }
01579
01580 html += "<table border=\"0\" cellspacing=\"0\"><tr><td> </td></tr><tr>";
01581
01582
01583
01584 switch ( msg->method() ) {
01585 case Scheduler::Publish:
01586 case Scheduler::Request:
01587 case Scheduler::Refresh:
01588 case Scheduler::Add:
01589 {
01590 if ( inc && inc->revision() > 0 && existingIncidence ) {
01591 if ( inc->type() == "Todo" ) {
01592 html += "<td colspan=\"9\">";
01593 html += helper->makeLink( "reply", i18n( "[Record invitation to my task list]" ) );
01594 } else {
01595 html += "<td colspan=\"13\">";
01596 html += helper->makeLink( "reply", i18n( "[Record invitation to my calendar]" ) );
01597 }
01598 html += "</td></tr><tr>";
01599 }
01600 html += "<td>";
01601
01602 if ( !myInc ) {
01603 if ( rsvpReq ) {
01604
01605 html += helper->makeLink( "accept", i18n( "[Accept]" ) );
01606 html += "</td><td> </td><td>";
01607 html += helper->makeLink( "accept_conditionally",
01608 i18n( "Accept conditionally", "[Accept cond.]" ) );
01609 html += "</td><td> </td><td>";
01610 }
01611
01612 if ( rsvpReq ) {
01613
01614 html += helper->makeLink( "counter", i18n( "[Counter proposal]" ) );
01615 html += "</td><td> </td><td>";
01616 }
01617
01618 if ( rsvpReq ) {
01619
01620 html += helper->makeLink( "decline", i18n( "[Decline]" ) );
01621 html += "</td><td> </td><td>";
01622 }
01623
01624 if ( !rsvpRec || ( inc && inc->revision() > 0 ) ) {
01625
01626 html += helper->makeLink( "delegate", i18n( "[Delegate]" ) );
01627 html += "</td><td> </td><td>";
01628
01629
01630 html += helper->makeLink( "forward", i18n( "[Forward]" ) );
01631
01632
01633 if ( inc->type() == "Event" ) {
01634 html += "</td><td> </td><td>";
01635 html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
01636 }
01637 }
01638 }
01639 break;
01640 }
01641
01642 case Scheduler::Cancel:
01643
01644 if ( existingIncidence ) {
01645 if ( inc->type() == "Todo" ) {
01646 html += helper->makeLink( "cancel", i18n( "[Remove invitation from my task list]" ) );
01647 } else {
01648 html += helper->makeLink( "cancel", i18n( "[Remove invitation from my calendar]" ) );
01649 }
01650 }
01651 break;
01652
01653 case Scheduler::Reply:
01654 {
01655
01656 Attendee *a = 0;
01657 Attendee *ea = 0;
01658 if ( inc ) {
01659 a = inc->attendees().first();
01660 if ( a && helper->calendar() ) {
01661 ea = findAttendee( existingIncidence, a->email() );
01662 }
01663 }
01664 if ( ea && ( ea->status() != Attendee::NeedsAction ) && ( ea->status() == a->status() ) ) {
01665 html += "<br/>";
01666 html += eventViewerAddTag( "i", i18n( "The response has already been recorded" ) );
01667 } else {
01668 if ( inc->type() == "Todo" ) {
01669 html += helper->makeLink( "reply", i18n( "[Record response into my task list]" ) );
01670 } else {
01671 html += helper->makeLink( "reply", i18n( "[Record response into my calendar]" ) );
01672 }
01673 }
01674 break;
01675 }
01676
01677 case Scheduler::Counter:
01678
01679 html += helper->makeLink( "accept_counter", i18n("[Accept]") );
01680 html += " ";
01681 html += helper->makeLink( "decline_counter", i18n("[Decline]") );
01682 html += " ";
01683 html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
01684 break;
01685
01686 case Scheduler::Declinecounter:
01687 case Scheduler::NoMethod:
01688 break;
01689 }
01690
01691
01692 html += "</td></tr></table>";
01693
01694
01695 if ( myInc && helper->calendar() ) {
01696 html += invitationAttendees( helper->calendar()->incidence( inc->uid() ) );
01697 }
01698
01699
01700 html += "</td></tr></table><br></div>";
01701 return html;
01702 }
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714 static QString stringProp( KTNEFMessage* tnefMsg, const Q_UINT32& key,
01715 const QString& fallback = QString::null)
01716 {
01717 return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16,
01718 fallback );
01719 }
01720
01721 static QString sNamedProp( KTNEFMessage* tnefMsg, const QString& name,
01722 const QString& fallback = QString::null )
01723 {
01724 return tnefMsg->findNamedProp( name, fallback );
01725 }
01726
01727 struct save_tz { char* old_tz; char* tz_env_str; };
01728
01729
01730 static struct save_tz set_tz( const char* _tc )
01731 {
01732 const char *tc = _tc?_tc:"UTC";
01733
01734 struct save_tz rv;
01735
01736 rv.old_tz = 0;
01737 rv.tz_env_str = 0;
01738
01739
01740
01741 char* tz_env = 0;
01742 if( getenv( "TZ" ) ) {
01743 tz_env = strdup( getenv( "TZ" ) );
01744 rv.old_tz = tz_env;
01745 }
01746 char* tmp_env = (char*)malloc( strlen( tc ) + 4 );
01747 strcpy( tmp_env, "TZ=" );
01748 strcpy( tmp_env+3, tc );
01749 putenv( tmp_env );
01750
01751 rv.tz_env_str = tmp_env;
01752
01753
01754
01755 tzset();
01756
01757
01758 return rv;
01759 }
01760
01761
01762 static void unset_tz( struct save_tz old_tz )
01763 {
01764 if( old_tz.old_tz ) {
01765 char* tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 );
01766 strcpy( tmp_env, "TZ=" );
01767 strcpy( tmp_env+3, old_tz.old_tz );
01768 putenv( tmp_env );
01769
01770 free( old_tz.old_tz );
01771 } else {
01772
01773 putenv( strdup("TZ") );
01774 }
01775 tzset();
01776
01777
01778 if( old_tz.tz_env_str ) free( old_tz.tz_env_str );
01779 }
01780
01781 static QDateTime utc2Local( const QDateTime& utcdt )
01782 {
01783 struct tm tmL;
01784
01785 save_tz tmp_tz = set_tz("UTC");
01786 time_t utc = utcdt.toTime_t();
01787 unset_tz( tmp_tz );
01788
01789 localtime_r( &utc, &tmL );
01790 return QDateTime( QDate( tmL.tm_year+1900, tmL.tm_mon+1, tmL.tm_mday ),
01791 QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
01792 }
01793
01794
01795 static QDateTime pureISOToLocalQDateTime( const QString& dtStr,
01796 bool bDateOnly = false )
01797 {
01798 QDate tmpDate;
01799 QTime tmpTime;
01800 int year, month, day, hour, minute, second;
01801
01802 if( bDateOnly ) {
01803 year = dtStr.left( 4 ).toInt();
01804 month = dtStr.mid( 4, 2 ).toInt();
01805 day = dtStr.mid( 6, 2 ).toInt();
01806 hour = 0;
01807 minute = 0;
01808 second = 0;
01809 } else {
01810 year = dtStr.left( 4 ).toInt();
01811 month = dtStr.mid( 4, 2 ).toInt();
01812 day = dtStr.mid( 6, 2 ).toInt();
01813 hour = dtStr.mid( 9, 2 ).toInt();
01814 minute = dtStr.mid( 11, 2 ).toInt();
01815 second = dtStr.mid( 13, 2 ).toInt();
01816 }
01817 tmpDate.setYMD( year, month, day );
01818 tmpTime.setHMS( hour, minute, second );
01819
01820 if( tmpDate.isValid() && tmpTime.isValid() ) {
01821 QDateTime dT = QDateTime( tmpDate, tmpTime );
01822
01823 if( !bDateOnly ) {
01824
01825 if (dtStr.at(dtStr.length()-1) == 'Z') {
01826
01827
01828 dT = utc2Local( dT );
01829 }
01830 }
01831 return dT;
01832 } else
01833 return QDateTime();
01834 }
01835
01836
01837
01838 QString IncidenceFormatter::msTNEFToVPart( const QByteArray& tnef )
01839 {
01840 bool bOk = false;
01841
01842 KTNEFParser parser;
01843 QBuffer buf( tnef );
01844 CalendarLocal cal ( QString::fromLatin1( "UTC" ) );
01845 KABC::Addressee addressee;
01846 KABC::VCardConverter cardConv;
01847 ICalFormat calFormat;
01848 Event* event = new Event();
01849
01850 if( parser.openDevice( &buf ) ) {
01851 KTNEFMessage* tnefMsg = parser.message();
01852
01853
01854
01855
01856 QString msgClass = tnefMsg->findProp( 0x001A, QString::null, true )
01857 .upper();
01858 if( !msgClass.isEmpty() ) {
01859
01860
01861 bool bCompatClassAppointment = false;
01862 bool bCompatMethodRequest = false;
01863 bool bCompatMethodCancled = false;
01864 bool bCompatMethodAccepted = false;
01865 bool bCompatMethodAcceptedCond = false;
01866 bool bCompatMethodDeclined = false;
01867 if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ) {
01868 bCompatClassAppointment = true;
01869 if( msgClass.endsWith( ".MTGREQ" ) )
01870 bCompatMethodRequest = true;
01871 if( msgClass.endsWith( ".MTGCNCL" ) )
01872 bCompatMethodCancled = true;
01873 if( msgClass.endsWith( ".MTGRESPP" ) )
01874 bCompatMethodAccepted = true;
01875 if( msgClass.endsWith( ".MTGRESPA" ) )
01876 bCompatMethodAcceptedCond = true;
01877 if( msgClass.endsWith( ".MTGRESPN" ) )
01878 bCompatMethodDeclined = true;
01879 }
01880 bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" );
01881
01882 if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) {
01883
01884 bool bIsReply = false;
01885 QString prodID = "-//Microsoft Corporation//Outlook ";
01886 prodID += tnefMsg->findNamedProp( "0x8554", "9.0" );
01887 prodID += "MIMEDIR/EN\n";
01888 prodID += "VERSION:2.0\n";
01889 calFormat.setApplication( "Outlook", prodID );
01890
01891 Scheduler::Method method;
01892 if( bCompatMethodRequest )
01893 method = Scheduler::Request;
01894 else if( bCompatMethodCancled )
01895 method = Scheduler::Cancel;
01896 else if( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
01897 bCompatMethodDeclined ) {
01898 method = Scheduler::Reply;
01899 bIsReply = true;
01900 } else {
01901
01902
01903
01904
01905
01906
01907
01908
01909 if( tnefMsg->findProp(0x0c17) == "1" )
01910 bIsReply = true;
01911 method = Scheduler::Request;
01912 }
01913
01915 ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown );
01916
01917 QString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) );
01918
01919 if( !sSenderSearchKeyEmail.isEmpty() ) {
01920 int colon = sSenderSearchKeyEmail.find( ':' );
01921
01922 if( sSenderSearchKeyEmail.find( ':' ) == -1 )
01923 sSenderSearchKeyEmail.remove( 0, colon+1 );
01924 }
01925
01926 QString s( tnefMsg->findProp( 0x0e04 ) );
01927 QStringList attendees = QStringList::split( ';', s );
01928 if( attendees.count() ) {
01929 for( QStringList::Iterator it = attendees.begin();
01930 it != attendees.end(); ++it ) {
01931
01932
01933 if( (*it).find('@') == -1 ) {
01934 s = (*it).stripWhiteSpace();
01935
01936 Attendee *attendee = new Attendee( s, s, true );
01937 if( bIsReply ) {
01938 if( bCompatMethodAccepted )
01939 attendee->setStatus( Attendee::Accepted );
01940 if( bCompatMethodDeclined )
01941 attendee->setStatus( Attendee::Declined );
01942 if( bCompatMethodAcceptedCond )
01943 attendee->setStatus(Attendee::Tentative);
01944 } else {
01945 attendee->setStatus( Attendee::NeedsAction );
01946 attendee->setRole( Attendee::ReqParticipant );
01947 }
01948 event->addAttendee(attendee);
01949 }
01950 }
01951 } else {
01952
01953
01954 s = sSenderSearchKeyEmail;
01955 if( !s.isEmpty() ) {
01956 Attendee *attendee = new Attendee( QString::null, QString::null,
01957 true );
01958 if( bIsReply ) {
01959 if( bCompatMethodAccepted )
01960 attendee->setStatus( Attendee::Accepted );
01961 if( bCompatMethodAcceptedCond )
01962 attendee->setStatus( Attendee::Declined );
01963 if( bCompatMethodDeclined )
01964 attendee->setStatus( Attendee::Tentative );
01965 } else {
01966 attendee->setStatus(Attendee::NeedsAction);
01967 attendee->setRole(Attendee::ReqParticipant);
01968 }
01969 event->addAttendee(attendee);
01970 }
01971 }
01972 s = tnefMsg->findProp( 0x0c1f );
01973 if( s.isEmpty() && !bIsReply )
01974 s = sSenderSearchKeyEmail;
01975
01976 if( !s.isEmpty() )
01977 event->setOrganizer( s );
01978
01979 s = tnefMsg->findProp( 0x8516 ).replace( QChar( '-' ), QString::null )
01980 .replace( QChar( ':' ), QString::null );
01981 event->setDtStart( QDateTime::fromString( s ) );
01982
01983 s = tnefMsg->findProp( 0x8517 ).replace( QChar( '-' ), QString::null )
01984 .replace( QChar( ':' ), QString::null );
01985 event->setDtEnd( QDateTime::fromString( s ) );
01986
01987 s = tnefMsg->findProp( 0x8208 );
01988 event->setLocation( s );
01989
01990
01991
01992
01993
01994
01995 s = tnefMsg->findProp( 0x0023 );
01996 event->setUid( s );
01997
01998
01999
02000
02001 s = tnefMsg->findProp( 0x8202 ).replace( QChar( '-' ), QString::null )
02002 .replace( QChar( ':' ), QString::null );
02003
02004
02005
02006 s = tnefMsg->findNamedProp( "Keywords" );
02007 event->setCategories( s );
02008
02009 s = tnefMsg->findProp( 0x1000 );
02010 event->setDescription( s );
02011
02012 s = tnefMsg->findProp( 0x0070 );
02013 event->setSummary( s );
02014
02015 s = tnefMsg->findProp( 0x0026 );
02016 event->setPriority( s.toInt() );
02017
02018
02019 if(!tnefMsg->findProp(0x8503).isEmpty()) {
02020 Alarm *alarm = new Alarm(event);
02021 QDateTime highNoonTime =
02022 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8502 )
02023 .replace( QChar( '-' ), "" )
02024 .replace( QChar( ':' ), "" ) );
02025 QDateTime wakeMeUpTime =
02026 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8560, "" )
02027 .replace( QChar( '-' ), "" )
02028 .replace( QChar( ':' ), "" ) );
02029 alarm->setTime(wakeMeUpTime);
02030
02031 if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
02032 alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
02033 else
02034
02035 alarm->setStartOffset( Duration( 15*60 ) );
02036 alarm->setDisplayAlarm( i18n( "Reminder" ) );
02037
02038
02039
02040 event->addAlarm( alarm );
02041 }
02042 cal.addEvent( event );
02043 bOk = true;
02044
02045 } else if( bCompatClassNote || "IPM.CONTACT" == msgClass ) {
02046 addressee.setUid( stringProp( tnefMsg, attMSGID ) );
02047 addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
02048 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true );
02049 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false );
02050 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false );
02051 addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
02052 addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
02053 addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
02054 addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
02055 addressee.insertCustom( "KADDRESSBOOK", "X-Department", stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
02056 addressee.insertCustom( "KADDRESSBOOK", "X-Office", stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
02057 addressee.insertCustom( "KADDRESSBOOK", "X-Profession", stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
02058
02059 QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY )
02060 .replace( QChar( '-' ), QString::null )
02061 .replace( QChar( ':' ), QString::null );
02062 if( !s.isEmpty() )
02063 addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s );
02064
02065 addressee.setUrl( KURL( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) );
02066
02067
02068 addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
02069 addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
02070 addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
02071 addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
02072 addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
02073
02074 addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
02075 addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
02076 addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
02077
02078
02079
02080
02081
02082 KABC::Address adr;
02083 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
02084 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
02085 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
02086 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
02087 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
02088 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
02089 adr.setType(KABC::Address::Home);
02090 addressee.insertAddress(adr);
02091
02092 adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
02093 adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
02094 adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
02095 adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
02096 adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
02097 adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
02098 adr.setType( KABC::Address::Work );
02099 addressee.insertAddress( adr );
02100
02101 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
02102 adr.setStreet( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
02103 adr.setLocality( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
02104 adr.setRegion( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
02105 adr.setPostalCode( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
02106 adr.setCountry( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
02107 adr.setType( KABC::Address::Dom );
02108 addressee.insertAddress(adr);
02109
02110
02111
02112
02113
02114 QString nr;
02115 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
02116 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) );
02117 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
02118 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) );
02119 nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
02120 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) );
02121 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
02122 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) );
02123 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
02124 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) );
02125
02126 s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY )
02127 .replace( QChar( '-' ), QString::null )
02128 .replace( QChar( ':' ), QString::null );
02129 if( !s.isEmpty() )
02130 addressee.setBirthday( QDateTime::fromString( s ) );
02131
02132 bOk = ( !addressee.isEmpty() );
02133 } else if( "IPM.NOTE" == msgClass ) {
02134
02135 }
02136 }
02137 }
02138
02139
02140 QString iCal = calFormat.toString( &cal );
02141 if( !iCal.isEmpty() )
02142
02143 return iCal;
02144
02145
02146 KABC::VCardConverter converter;
02147 return converter.createVCard( addressee );
02148 }
02149
02150
02151 QString IncidenceFormatter::formatTNEFInvitation( const QByteArray& tnef,
02152 Calendar *mCalendar, InvitationFormatterHelper *helper )
02153 {
02154 QString vPart = IncidenceFormatter::msTNEFToVPart( tnef );
02155 QString iCal = IncidenceFormatter::formatICalInvitation( vPart, mCalendar, helper );
02156 if( !iCal.isEmpty() )
02157 return iCal;
02158 return vPart;
02159 }
02160
02161
02162
02163
02164
02165
02166
02167
02168 class IncidenceFormatter::ToolTipVisitor : public IncidenceBase::Visitor
02169 {
02170 public:
02171 ToolTipVisitor() : mRichText( true ), mResult( "" ) {}
02172
02173 bool act( IncidenceBase *incidence, bool richText=true)
02174 {
02175 mRichText = richText;
02176 mResult = "";
02177 return incidence ? incidence->accept( *this ) : false;
02178 }
02179 QString result() const { return mResult; }
02180
02181 protected:
02182 bool visit( Event *event );
02183 bool visit( Todo *todo );
02184 bool visit( Journal *journal );
02185 bool visit( FreeBusy *fb );
02186
02187 QString dateRangeText( Event*event );
02188 QString dateRangeText( Todo *todo );
02189 QString dateRangeText( Journal *journal );
02190 QString dateRangeText( FreeBusy *fb );
02191
02192 QString generateToolTip( Incidence* incidence, QString dtRangeText );
02193
02194 protected:
02195 bool mRichText;
02196 QString mResult;
02197 };
02198
02199 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Event*event )
02200 {
02201 QString ret;
02202 QString tmp;
02203 if ( event->isMultiDay() ) {
02204
02205 tmp = "<br>" + i18n("Event start", "<i>From:</i> %1");
02206 if (event->doesFloat())
02207 ret += tmp.arg( event->dtStartDateStr().replace(" ", " ") );
02208 else
02209 ret += tmp.arg( event->dtStartStr().replace(" ", " ") );
02210
02211 tmp = "<br>" + i18n("Event end","<i>To:</i> %1");
02212 if (event->doesFloat())
02213 ret += tmp.arg( event->dtEndDateStr().replace(" ", " ") );
02214 else
02215 ret += tmp.arg( event->dtEndStr().replace(" ", " ") );
02216
02217 } else {
02218
02219 ret += "<br>"+i18n("<i>Date:</i> %1").
02220 arg( event->dtStartDateStr().replace(" ", " ") );
02221 if ( !event->doesFloat() ) {
02222 const QString dtStartTime = event->dtStartTimeStr().replace( " ", " " );
02223 const QString dtEndTime = event->dtEndTimeStr().replace( " ", " " );
02224 if ( dtStartTime == dtEndTime ) {
02225 tmp = "<br>" + i18n("time for event, to prevent ugly line breaks",
02226 "<i>Time:</i> %1").
02227 arg( dtStartTime );
02228 } else {
02229 tmp = "<br>" + i18n("time range for event, to prevent ugly line breaks",
02230 "<i>Time:</i> %1 - %2").
02231 arg( dtStartTime, dtEndTime );
02232 }
02233 ret += tmp;
02234 }
02235
02236 }
02237 return ret;
02238 }
02239
02240 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Todo*todo )
02241 {
02242 QString ret;
02243 bool floats( todo->doesFloat() );
02244 if (todo->hasStartDate())
02245
02246
02247
02248 ret += "<br>" + i18n("<i>Start:</i> %1").arg(
02249 (floats)
02250 ?(todo->dtStartDateStr().replace(" ", " "))
02251 :(todo->dtStartStr().replace(" ", " ")) ) ;
02252 if (todo->hasDueDate())
02253 ret += "<br>" + i18n("<i>Due:</i> %1").arg(
02254 (floats)
02255 ?(todo->dtDueDateStr().replace(" ", " "))
02256 :(todo->dtDueStr().replace(" ", " ")) );
02257 if (todo->isCompleted())
02258 ret += "<br>" + i18n("<i>Completed:</i> %1").arg( todo->completedStr().replace(" ", " ") );
02259 else
02260 ret += "<br>" + i18n("%1 % completed").arg(todo->percentComplete());
02261
02262 return ret;
02263 }
02264
02265 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Journal*journal )
02266 {
02267 QString ret;
02268 if (journal->dtStart().isValid() ) {
02269 ret += "<br>" + i18n("<i>Date:</i> %1").arg( journal->dtStartDateStr( false ) );
02270 }
02271 return ret;
02272 }
02273
02274 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( FreeBusy *fb )
02275 {
02276 QString tmp( "<br>" + i18n("<i>Period start:</i> %1") );
02277 QString ret = tmp.arg( KGlobal::locale()->formatDateTime( fb->dtStart() ) );
02278 tmp = "<br>" + i18n("<i>Period start:</i> %1");
02279 ret += tmp.arg( KGlobal::locale()->formatDateTime( fb->dtEnd() ) );
02280 return ret;
02281 }
02282
02283
02284
02285 bool IncidenceFormatter::ToolTipVisitor::visit( Event *event )
02286 {
02287 mResult = generateToolTip( event, dateRangeText( event ) );
02288 return !mResult.isEmpty();
02289 }
02290
02291 bool IncidenceFormatter::ToolTipVisitor::visit( Todo *todo )
02292 {
02293 mResult = generateToolTip( todo, dateRangeText( todo ) );
02294 return !mResult.isEmpty();
02295 }
02296
02297 bool IncidenceFormatter::ToolTipVisitor::visit( Journal *journal )
02298 {
02299 mResult = generateToolTip( journal, dateRangeText( journal ) );
02300 return !mResult.isEmpty();
02301 }
02302
02303 bool IncidenceFormatter::ToolTipVisitor::visit( FreeBusy *fb )
02304 {
02305 mResult = "<qt><b>" + i18n("Free/Busy information for %1")
02306 .arg(fb->organizer().fullName()) + "</b>";
02307 mResult += dateRangeText( fb );
02308 mResult += "</qt>";
02309 return !mResult.isEmpty();
02310 }
02311
02312 QString IncidenceFormatter::ToolTipVisitor::generateToolTip( Incidence* incidence, QString dtRangeText )
02313 {
02314 if ( !incidence )
02315 return QString::null;
02316
02317 QString tmp = "<qt><b>"+ incidence->summary().replace("\n", "<br>")+"</b>";
02318
02319 tmp += dtRangeText;
02320
02321 if (!incidence->location().isEmpty()) {
02322
02323 tmp += "<br>"+i18n("<i>Location:</i> %1").
02324 arg( incidence->location().replace("\n", "<br>") );
02325 }
02326 if (!incidence->description().isEmpty()) {
02327 QString desc(incidence->description());
02328 if (desc.length()>120) {
02329 desc = desc.left(120) + "...";
02330 }
02331 tmp += "<br>----------<br>" + i18n("<i>Description:</i><br>") + desc.replace("\n", "<br>");
02332 }
02333 tmp += "</qt>";
02334 return tmp;
02335 }
02336
02337 QString IncidenceFormatter::toolTipString( IncidenceBase *incidence, bool richText )
02338 {
02339 ToolTipVisitor v;
02340 if ( v.act( incidence, richText ) ) {
02341 return v.result();
02342 } else
02343 return QString::null;
02344 }
02345
02346
02347
02348
02349
02350
02351
02352
02353 class IncidenceFormatter::MailBodyVisitor : public IncidenceBase::Visitor
02354 {
02355 public:
02356 MailBodyVisitor() : mResult( "" ) {}
02357
02358 bool act( IncidenceBase *incidence )
02359 {
02360 mResult = "";
02361 return incidence ? incidence->accept( *this ) : false;
02362 }
02363 QString result() const { return mResult; }
02364
02365 protected:
02366 bool visit( Event *event );
02367 bool visit( Todo *todo );
02368 bool visit( Journal *journal );
02369 bool visit( FreeBusy * ) { mResult = i18n("This is a Free Busy Object"); return !mResult.isEmpty(); }
02370 protected:
02371 QString mResult;
02372 };
02373
02374
02375 static QString mailBodyIncidence( Incidence *incidence )
02376 {
02377 QString body;
02378 if ( !incidence->summary().isEmpty() ) {
02379 body += i18n("Summary: %1\n").arg( incidence->summary() );
02380 }
02381 if ( !incidence->organizer().isEmpty() ) {
02382 body += i18n("Organizer: %1\n").arg( incidence->organizer().fullName() );
02383 }
02384 if ( !incidence->location().isEmpty() ) {
02385 body += i18n("Location: %1\n").arg( incidence->location() );
02386 }
02387 return body;
02388 }
02389
02390 bool IncidenceFormatter::MailBodyVisitor::visit( Event *event )
02391 {
02392 QString recurrence[]= {i18n("no recurrence", "None"),
02393 i18n("Minutely"), i18n("Hourly"), i18n("Daily"),
02394 i18n("Weekly"), i18n("Monthly Same Day"), i18n("Monthly Same Position"),
02395 i18n("Yearly"), i18n("Yearly"), i18n("Yearly")};
02396
02397 mResult = mailBodyIncidence( event );
02398 mResult += i18n("Start Date: %1\n").arg( event->dtStartDateStr() );
02399 if ( !event->doesFloat() ) {
02400 mResult += i18n("Start Time: %1\n").arg( event->dtStartTimeStr() );
02401 }
02402 if ( event->dtStart() != event->dtEnd() ) {
02403 mResult += i18n("End Date: %1\n").arg( event->dtEndDateStr() );
02404 }
02405 if ( !event->doesFloat() ) {
02406 mResult += i18n("End Time: %1\n").arg( event->dtEndTimeStr() );
02407 }
02408 if ( event->doesRecur() ) {
02409 Recurrence *recur = event->recurrence();
02410
02411 mResult += i18n("Recurs: %1\n")
02412 .arg( recurrence[ recur->recurrenceType() ] );
02413 mResult += i18n("Frequency: %1\n")
02414 .arg( event->recurrence()->frequency() );
02415
02416 if ( recur->duration() > 0 ) {
02417 mResult += i18n ("Repeats once", "Repeats %n times", recur->duration());
02418 mResult += '\n';
02419 } else {
02420 if ( recur->duration() != -1 ) {
02421
02422 QString endstr;
02423 if ( event->doesFloat() ) {
02424 endstr = KGlobal::locale()->formatDate( recur->endDate() );
02425 } else {
02426 endstr = KGlobal::locale()->formatDateTime( recur->endDateTime() );
02427 }
02428 mResult += i18n("Repeat until: %1\n").arg( endstr );
02429 } else {
02430 mResult += i18n("Repeats forever\n");
02431 }
02432 }
02433 }
02434 QString details = event->description();
02435 if ( !details.isEmpty() ) {
02436 mResult += i18n("Details:\n%1\n").arg( details );
02437 }
02438 return !mResult.isEmpty();
02439 }
02440
02441 bool IncidenceFormatter::MailBodyVisitor::visit( Todo *todo )
02442 {
02443 mResult = mailBodyIncidence( todo );
02444
02445 if ( todo->hasStartDate() ) {
02446 mResult += i18n("Start Date: %1\n").arg( todo->dtStartDateStr() );
02447 if ( !todo->doesFloat() ) {
02448 mResult += i18n("Start Time: %1\n").arg( todo->dtStartTimeStr() );
02449 }
02450 }
02451 if ( todo->hasDueDate() ) {
02452 mResult += i18n("Due Date: %1\n").arg( todo->dtDueDateStr() );
02453 if ( !todo->doesFloat() ) {
02454 mResult += i18n("Due Time: %1\n").arg( todo->dtDueTimeStr() );
02455 }
02456 }
02457 QString details = todo->description();
02458 if ( !details.isEmpty() ) {
02459 mResult += i18n("Details:\n%1\n").arg( details );
02460 }
02461 return !mResult.isEmpty();
02462 }
02463
02464 bool IncidenceFormatter::MailBodyVisitor::visit( Journal *journal )
02465 {
02466 mResult = mailBodyIncidence( journal );
02467 mResult += i18n("Date: %1\n").arg( journal->dtStartDateStr() );
02468 if ( !journal->doesFloat() ) {
02469 mResult += i18n("Time: %1\n").arg( journal->dtStartTimeStr() );
02470 }
02471 if ( !journal->description().isEmpty() )
02472 mResult += i18n("Text of the journal:\n%1\n").arg( journal->description() );
02473 return !mResult.isEmpty();
02474 }
02475
02476
02477
02478 QString IncidenceFormatter::mailBodyString( IncidenceBase *incidence )
02479 {
02480 if ( !incidence )
02481 return QString::null;
02482
02483 MailBodyVisitor v;
02484 if ( v.act( incidence ) ) {
02485 return v.result();
02486 }
02487 return QString::null;
02488 }
02489
02490 QString IncidenceFormatter::recurrenceString(Incidence * incidence)
02491 {
02492 if ( !incidence->doesRecur() )
02493 return i18n( "No recurrence" );
02494
02495
02496 QStringList dayList;
02497 dayList.append( i18n( "31st Last" ) );
02498 dayList.append( i18n( "30th Last" ) );
02499 dayList.append( i18n( "29th Last" ) );
02500 dayList.append( i18n( "28th Last" ) );
02501 dayList.append( i18n( "27th Last" ) );
02502 dayList.append( i18n( "26th Last" ) );
02503 dayList.append( i18n( "25th Last" ) );
02504 dayList.append( i18n( "24th Last" ) );
02505 dayList.append( i18n( "23rd Last" ) );
02506 dayList.append( i18n( "22nd Last" ) );
02507 dayList.append( i18n( "21st Last" ) );
02508 dayList.append( i18n( "20th Last" ) );
02509 dayList.append( i18n( "19th Last" ) );
02510 dayList.append( i18n( "18th Last" ) );
02511 dayList.append( i18n( "17th Last" ) );
02512 dayList.append( i18n( "16th Last" ) );
02513 dayList.append( i18n( "15th Last" ) );
02514 dayList.append( i18n( "14th Last" ) );
02515 dayList.append( i18n( "13th Last" ) );
02516 dayList.append( i18n( "12th Last" ) );
02517 dayList.append( i18n( "11th Last" ) );
02518 dayList.append( i18n( "10th Last" ) );
02519 dayList.append( i18n( "9th Last" ) );
02520 dayList.append( i18n( "8th Last" ) );
02521 dayList.append( i18n( "7th Last" ) );
02522 dayList.append( i18n( "6th Last" ) );
02523 dayList.append( i18n( "5th Last" ) );
02524 dayList.append( i18n( "4th Last" ) );
02525 dayList.append( i18n( "3rd Last" ) );
02526 dayList.append( i18n( "2nd Last" ) );
02527 dayList.append( i18n( "last day of the month", "Last" ) );
02528 dayList.append( i18n( "unknown day of the month", "unknown" ) );
02529 dayList.append( i18n( "1st" ) );
02530 dayList.append( i18n( "2nd" ) );
02531 dayList.append( i18n( "3rd" ) );
02532 dayList.append( i18n( "4th" ) );
02533 dayList.append( i18n( "5th" ) );
02534
02535 QString recurString;
02536 const KCalendarSystem *calSys = KGlobal::locale()->calendar();;
02537
02538 Recurrence *recurs = incidence->recurrence();
02539 switch ( recurs->recurrenceType() ) {
02540
02541 case Recurrence::rNone:
02542 recurString = i18n( "no recurrence", "None" );
02543 break;
02544 case Recurrence::rDaily:
02545 recurString = i18n( "Every day", "Every %1 days", recurs->frequency() );
02546 break;
02547 case Recurrence::rWeekly:
02548 {
02549 QString dayNames;
02550
02551 int weekStart = KGlobal::locale()->weekStartDay();
02552 bool addSpace = false;
02553 for ( int i = 0; i < 7; ++i ) {
02554 if ( recurs->days().testBit( (i+weekStart+6)%7 )) {
02555 if (addSpace) dayNames.append(" ");
02556 dayNames.append( calSys->weekDayName( ((i+weekStart+6)%7)+1, true ) );
02557 addSpace=true;
02558 }
02559 }
02560 recurString = i18n( "Every week on %1",
02561 "Every %n weeks on %1",
02562 recurs->frequency()).arg( dayNames );
02563 break;
02564 }
02565 case Recurrence::rMonthlyPos:
02566 {
02567 KCal::RecurrenceRule::WDayPos rule = recurs->monthPositions()[0];
02568 recurString = i18n( "Every month on the %1 %2",
02569 "Every %n months on the %1 %2",
02570 recurs->frequency() ).arg(dayList[rule.pos() + 31]).arg(
02571 calSys->weekDayName( rule.day(),false ) );
02572 break;
02573 }
02574 case Recurrence::rMonthlyDay:
02575 {
02576 int days = recurs->monthDays()[0];
02577 if (days < 0) {
02578 recurString = i18n( "Every month on the %1 day",
02579 "Every %n months on the %1 day",
02580 recurs->frequency() ).arg( dayList[days + 31] );
02581 } else {
02582 recurString = i18n( "Every month on day %1",
02583 "Every %n months on day %1",
02584 recurs->frequency() ).arg( recurs->monthDays()[0] );
02585 }
02586 break;
02587 }
02588
02589 case Recurrence::rYearlyMonth:
02590 {
02591 recurString = i18n( "Every year on day %1 of %2",
02592 "Every %n years on day %1 of %2",
02593 recurs->frequency() )
02594 .arg(recurs->yearDates()[0])
02595 .arg(calSys->monthName( recurs->yearMonths()[0], recurs->startDate().year() ) );
02596 break;
02597 }
02598 case Recurrence::rYearlyPos:
02599 {
02600 KCal::RecurrenceRule::WDayPos rule = recurs->yearPositions()[0];
02601 recurString = i18n( "Every year on the %1 %2 of %3",
02602 "Every %n years on the %1 %2of %3",
02603 recurs->frequency()).arg( dayList[rule.pos() + 31] )
02604 .arg( calSys->weekDayName( rule.day(), false ))
02605 .arg( calSys->monthName( recurs->yearMonths()[0], recurs->startDate().year() ) );
02606 break;
02607 }
02608 case Recurrence::rYearlyDay:
02609 {
02610 recurString = i18n( "Every year on day %1",
02611 "Every %n years on day %1",
02612 recurs->frequency()).arg( recurs->yearDays()[0] );
02613 break;
02614 }
02615
02616 default:
02617 return i18n( "Incidence recurs" );
02618 }
02619
02620 return recurString;
02621 }