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