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 #include <kmimetype.h>
00053
00054 #include <qbuffer.h>
00055 #include <qstylesheet.h>
00056 #include <qdatetime.h>
00057
00058 #include <time.h>
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::convertFromPlainText(str, QStyleSheetItem::WhiteSpaceNormal);
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 if ( !incidence ) {
00727 return false;
00728 }
00729
00730
00731
00732 bool rsvp = true;
00733 Attendee::List attendees = incidence->attendees();
00734 Attendee::List::ConstIterator it;
00735 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
00736 if ( it == attendees.begin() ) {
00737 rsvp = (*it)->RSVP();
00738 } else {
00739 if ( (*it)->RSVP() != rsvp ) {
00740 rsvp = true;
00741 break;
00742 }
00743 }
00744 }
00745 return rsvp;
00746 }
00747
00748 static QString rsvpRequestedStr( bool rsvpRequested )
00749 {
00750 if ( rsvpRequested ) {
00751 return i18n( "Your response is requested" );
00752 } else {
00753 return i18n( "A response is not necessary" );
00754 }
00755 }
00756
00757 static QString invitationPerson( const QString& email, QString name, QString uid )
00758 {
00759
00760
00761 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
00762 KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
00763 KABC::Addressee::List addressList = add_book->findByEmail( email );
00764 if ( !addressList.isEmpty() ) {
00765 KABC::Addressee o = addressList.first();
00766 if ( !o.isEmpty() && addressList.size() < 2 ) {
00767 if ( name.isEmpty() ) {
00768
00769 name = o.formattedName();
00770 }
00771 uid = o.uid();
00772 } else {
00773
00774 uid = QString::null;
00775 }
00776 }
00777 }
00778
00779
00780 QString tmpString;
00781 if ( !uid.isEmpty() ) {
00782
00783 if ( name.isEmpty() ) {
00784
00785 tmpString += eventViewerAddLink( "uid:" + uid, email );
00786 } else {
00787 tmpString += eventViewerAddLink( "uid:" + uid, name );
00788 }
00789 } else {
00790
00791 tmpString += ( name.isEmpty() ? email : name );
00792 }
00793 tmpString += '\n';
00794
00795
00796 if ( !email.isEmpty() ) {
00797 KCal::Person person( name, email );
00798 KURL mailto;
00799 mailto.setProtocol( "mailto" );
00800 mailto.setPath( person.fullName() );
00801 const QString iconPath =
00802 KGlobal::iconLoader()->iconPath( "mail_new", KIcon::Small );
00803 tmpString += eventViewerAddLink( mailto.url(), "<img src=\"" + iconPath + "\">" )
00804 ;
00805 }
00806 tmpString += "\n";
00807
00808 return tmpString;
00809 }
00810
00811 static QString invitationsDetailsIncidence( Incidence *incidence )
00812 {
00813 QString html;
00814 QString descr;
00815 QStringList comments;
00816 if ( incidence->comments().isEmpty() && !incidence->description().isEmpty() ) {
00817 comments << incidence->description();
00818 } else {
00819 descr = incidence->description();
00820 comments = incidence->comments();
00821 }
00822
00823 if( !descr.isEmpty() ) {
00824 html += "<br/><u>" + i18n("Description:")
00825 + "</u><table border=\"0\"><tr><td> </td><td>";
00826 html += string2HTML(descr) + "</td></tr></table>";
00827 }
00828 if ( !comments.isEmpty() ) {
00829 html += "<br><u>" + i18n("Comments:")
00830 + "</u><table border=\"0\"><tr><td> </td><td>";
00831 if ( comments.count() > 1 ) {
00832 html += "<ul>";
00833 for ( uint i = 0; i < comments.count(); ++i )
00834 html += "<li>" + string2HTML( comments[i] ) + "</li>";
00835 html += "</ul>";
00836 } else {
00837 html += string2HTML( comments[0] );
00838 }
00839 html += "</td></tr></table>";
00840 }
00841 return html;
00842 }
00843
00844 static QString invitationDetailsEvent( Event* event )
00845 {
00846
00847 if ( !event )
00848 return QString::null;
00849
00850 QString html;
00851 QString tmp;
00852
00853 QString sSummary = i18n( "Summary unspecified" );
00854 if ( ! event->summary().isEmpty() ) {
00855 sSummary = QStyleSheet::escape( event->summary() );
00856 }
00857
00858 QString sLocation = i18n( "Location unspecified" );
00859 if ( ! event->location().isEmpty() ) {
00860 sLocation = QStyleSheet::escape( event->location() );
00861 }
00862
00863 QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00864 html = QString("<div dir=\"%1\">\n").arg(dir);
00865
00866 html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
00867
00868
00869 html += invitationRow( i18n( "What:" ), sSummary );
00870 html += invitationRow( i18n( "Where:" ), sLocation );
00871
00872
00873 if ( event->dtStart().date() == event->dtEnd().date() ) {
00874 html += invitationRow( i18n( "Date:" ), event->dtStartDateStr( false ) );
00875 if ( !event->doesFloat() ) {
00876 html += invitationRow( i18n( "Time:" ),
00877 event->dtStartTimeStr() + " - " + event->dtEndTimeStr() );
00878 }
00879 } else {
00880 html += invitationRow( i18n( "Starting date of an event", "From:" ), event->dtStartDateStr( false ) );
00881 if ( !event->doesFloat() ) {
00882 html += invitationRow( i18n( "Starting time of an event", "At:" ), event->dtStartTimeStr() );
00883 }
00884 if ( event->hasEndDate() ) {
00885 html += invitationRow( i18n( "Ending date of an event", "To:" ), event->dtEndDateStr( false ) );
00886 if ( !event->doesFloat() ) {
00887 html += invitationRow( i18n( "Starting time of an event", "At:" ), event->dtEndTimeStr() );
00888 }
00889 } else {
00890 html += invitationRow( i18n( "Ending date of an event", "To:" ), i18n( "no end date specified" ) );
00891 }
00892 }
00893
00894
00895 if ( !event->doesFloat() && event->hasEndDate() ) {
00896 tmp = QString::null;
00897 QTime sDuration(0,0,0), t;
00898 int secs = event->dtStart().secsTo( event->dtEnd() );
00899 t = sDuration.addSecs( secs );
00900 if ( t.hour() > 0 ) {
00901 tmp += i18n( "1 hour ", "%n hours ", t.hour() );
00902 }
00903 if ( t.minute() > 0 ) {
00904 tmp += i18n( "1 minute ", "%n minutes ", t.minute() );
00905 }
00906
00907 html += invitationRow( i18n( "Duration:" ), tmp );
00908 }
00909
00910 if ( event->doesRecur() )
00911 html += invitationRow( i18n( "Recurrence:" ), IncidenceFormatter::recurrenceString( event ) );
00912
00913 html += "</table>\n";
00914 html += invitationsDetailsIncidence( event );
00915 html += "</div>\n";
00916
00917 return html;
00918 }
00919
00920 static QString invitationDetailsTodo( Todo *todo )
00921 {
00922
00923 if ( !todo )
00924 return QString::null;
00925
00926 QString sSummary = i18n( "Summary unspecified" );
00927 if ( ! todo->summary().isEmpty() ) {
00928 sSummary = QStyleSheet::escape( todo->summary() );
00929 }
00930
00931 QString sLocation = i18n( "Location unspecified" );
00932 if ( ! todo->location().isEmpty() ) {
00933 sLocation = QStyleSheet::escape( todo->location() );
00934 }
00935
00936 QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00937 QString html = QString("<div dir=\"%1\">\n").arg(dir);
00938
00939 html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
00940
00941
00942 html += invitationRow( i18n( "What:" ), sSummary );
00943 html += invitationRow( i18n( "Where:" ), sLocation );
00944
00945 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
00946 html += invitationRow( i18n( "Start Date:" ), todo->dtStartStr( false ) );
00947 }
00948 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
00949 html += invitationRow( i18n( "Due Date:" ), todo->dtDueDateStr( false ) );
00950 if ( !todo->doesFloat() ) {
00951 html += invitationRow( i18n( "Due Time:" ),
00952 KGlobal::locale()->formatTime( todo->dtDue().time() ) );
00953 }
00954
00955 } else {
00956 html += invitationRow( i18n( "Due Date:" ), i18n( "Due Date: None", "None" ) );
00957 }
00958
00959 html += "</table></div>\n";
00960 html += invitationsDetailsIncidence( todo );
00961
00962 return html;
00963 }
00964
00965 static QString invitationDetailsJournal( Journal *journal )
00966 {
00967 if ( !journal )
00968 return QString::null;
00969
00970 QString sSummary = i18n( "Summary unspecified" );
00971 QString sDescr = i18n( "Description unspecified" );
00972 if ( ! journal->summary().isEmpty() ) {
00973 sSummary = journal->summary();
00974 }
00975 if ( ! journal->description().isEmpty() ) {
00976 sDescr = journal->description();
00977 }
00978 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00979 html += invitationRow( i18n( "Summary:" ), sSummary );
00980 html += invitationRow( i18n( "Date:" ), journal->dtStartDateStr( false ) );
00981 html += invitationRow( i18n( "Description:" ), sDescr );
00982 html += "</table>\n";
00983 html += invitationsDetailsIncidence( journal );
00984
00985 return html;
00986 }
00987
00988 static QString invitationDetailsFreeBusy( FreeBusy *fb )
00989 {
00990 if ( !fb )
00991 return QString::null;
00992 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00993
00994 html += invitationRow( i18n("Person:"), fb->organizer().fullName() );
00995 html += invitationRow( i18n("Start date:"), fb->dtStartDateStr() );
00996 html += invitationRow( i18n("End date:"),
00997 KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) );
00998 html += "<tr><td colspan=2><hr></td></tr>\n";
00999 html += "<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n";
01000
01001 QValueList<Period> periods = fb->busyPeriods();
01002
01003 QValueList<Period>::iterator it;
01004 for ( it = periods.begin(); it != periods.end(); ++it ) {
01005 Period per = *it;
01006 if ( per.hasDuration() ) {
01007 int dur = per.duration().asSeconds();
01008 QString cont;
01009 if ( dur >= 3600 ) {
01010 cont += i18n("1 hour ", "%n hours ", dur / 3600);
01011 dur %= 3600;
01012 }
01013 if ( dur >= 60 ) {
01014 cont += i18n("1 minute", "%n minutes ", dur / 60);
01015 dur %= 60;
01016 }
01017 if ( dur > 0 ) {
01018 cont += i18n("1 second", "%n seconds", dur);
01019 }
01020 html += invitationRow( QString::null, i18n("startDate for duration", "%1 for %2")
01021 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
01022 .arg(cont) );
01023 } else {
01024 QString cont;
01025 if ( per.start().date() == per.end().date() ) {
01026 cont = i18n("date, fromTime - toTime ", "%1, %2 - %3")
01027 .arg( KGlobal::locale()->formatDate( per.start().date() ) )
01028 .arg( KGlobal::locale()->formatTime( per.start().time() ) )
01029 .arg( KGlobal::locale()->formatTime( per.end().time() ) );
01030 } else {
01031 cont = i18n("fromDateTime - toDateTime", "%1 - %2")
01032 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
01033 .arg( KGlobal::locale()->formatDateTime( per.end(), false ) );
01034 }
01035
01036 html += invitationRow( QString::null, cont );
01037 }
01038 }
01039
01040 html += "</table>\n";
01041 return html;
01042 }
01043
01044 static QString invitationHeaderEvent( Event *event, ScheduleMessage *msg )
01045 {
01046 if ( !msg || !event )
01047 return QString::null;
01048
01049 switch ( msg->method() ) {
01050 case Scheduler::Publish:
01051 return i18n( "This event has been published" );
01052 case Scheduler::Request:
01053 if ( event->revision() > 0 ) {
01054 return i18n( "This invitation has been updated" );
01055 }
01056 if ( iamOrganizer( event ) ) {
01057 return i18n( "I sent this invitation" );
01058 } else {
01059 if ( !event->organizer().fullName().isEmpty() ) {
01060 return i18n( "You received an invitation from %1" ).
01061 arg( event->organizer().fullName() );
01062 } else {
01063 return i18n( "You received an invitation" );
01064 }
01065 }
01066 case Scheduler::Refresh:
01067 return i18n( "This invitation was refreshed" );
01068 case Scheduler::Cancel:
01069 return i18n( "This invitation has been canceled" );
01070 case Scheduler::Add:
01071 return i18n( "Addition to the invitation" );
01072 case Scheduler::Reply: {
01073 Attendee::List attendees = event->attendees();
01074 if( attendees.count() == 0 ) {
01075 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
01076 return QString::null;
01077 }
01078 if( attendees.count() != 1 ) {
01079 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
01080 << "but is " << attendees.count() << endl;
01081 }
01082 Attendee* attendee = *attendees.begin();
01083 QString attendeeName = attendee->name();
01084 if ( attendeeName.isEmpty() ) {
01085 attendeeName = attendee->email();
01086 }
01087 if ( attendeeName.isEmpty() ) {
01088 attendeeName = i18n( "Sender" );
01089 }
01090
01091 QString delegatorName, dummy;
01092 KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
01093 if ( delegatorName.isEmpty() ) {
01094 delegatorName = attendee->delegator();
01095 }
01096
01097 switch( attendee->status() ) {
01098 case Attendee::NeedsAction:
01099 return i18n( "%1 indicates this invitation still needs some action" ).arg( attendeeName );
01100 case Attendee::Accepted:
01101 if ( delegatorName.isEmpty() ) {
01102 return i18n( "%1 accepts this invitation" ).arg( attendeeName );
01103 } else {
01104 return i18n( "%1 accepts this invitation on behalf of %2" ).
01105 arg( attendeeName ).arg( delegatorName );
01106 }
01107 case Attendee::Tentative:
01108 if ( delegatorName.isEmpty() ) {
01109 return i18n( "%1 tentatively accepts this invitation" ).
01110 arg( attendeeName );
01111 } else {
01112 return i18n( "%1 tentatively accepts this invitation on behalf of %2" ).
01113 arg( attendeeName ).arg( delegatorName );
01114 }
01115 case Attendee::Declined:
01116 if ( delegatorName.isEmpty() ) {
01117 return i18n( "%1 declines this invitation" ).arg( attendeeName );
01118 } else {
01119 return i18n( "%1 declines this invitation on behalf of %2" ).
01120 arg( attendeeName ).arg( delegatorName );
01121 }
01122 case Attendee::Delegated: {
01123 QString delegate, dummy;
01124 KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
01125 if ( delegate.isEmpty() ) {
01126 delegate = attendee->delegate();
01127 }
01128 if ( !delegate.isEmpty() ) {
01129 return i18n( "%1 has delegated this invitation to %2" ).
01130 arg( attendeeName ) .arg( delegate );
01131 } else {
01132 return i18n( "%1 has delegated this invitation" ).arg( attendeeName );
01133 }
01134 }
01135 case Attendee::Completed:
01136 return i18n( "This invitation is now completed" );
01137 case Attendee::InProcess:
01138 return i18n( "%1 is still processing the invitation" ).
01139 arg( attendeeName );
01140 default:
01141 return i18n( "Unknown response to this invitation" );
01142 }
01143 break; }
01144 case Scheduler::Counter:
01145 return i18n( "Sender makes this counter proposal" );
01146 case Scheduler::Declinecounter:
01147 return i18n( "Sender declines the counter proposal" );
01148 case Scheduler::NoMethod:
01149 return i18n("Error: iMIP message with unknown method: '%1'").
01150 arg( msg->method() );
01151 }
01152 return QString::null;
01153 }
01154
01155 static QString invitationHeaderTodo( Todo *todo, ScheduleMessage *msg )
01156 {
01157 if ( !msg || !todo ) {
01158 return QString::null;
01159 }
01160
01161 switch ( msg->method() ) {
01162 case Scheduler::Publish:
01163 return i18n("This task has been published");
01164 case Scheduler::Request:
01165 if ( todo->revision() > 0 ) {
01166 return i18n( "This task has been updated" );
01167 } else {
01168 return i18n( "You have been assigned this task" );
01169 }
01170 case Scheduler::Refresh:
01171 return i18n( "This task was refreshed" );
01172 case Scheduler::Cancel:
01173 return i18n( "This task was canceled" );
01174 case Scheduler::Add:
01175 return i18n( "Addition to the task" );
01176 case Scheduler::Reply: {
01177 Attendee::List attendees = todo->attendees();
01178 if( attendees.count() == 0 ) {
01179 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
01180 return QString::null;
01181 }
01182 if( attendees.count() != 1 ) {
01183 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
01184 << "but is " << attendees.count() << endl;
01185 }
01186 Attendee* attendee = *attendees.begin();
01187
01188 switch( attendee->status() ) {
01189 case Attendee::NeedsAction:
01190 return i18n( "Sender indicates this task assignment still needs some action" );
01191 case Attendee::Accepted:
01192 return i18n( "Sender accepts this task" );
01193 case Attendee::Tentative:
01194 return i18n( "Sender tentatively accepts this task" );
01195 case Attendee::Declined:
01196 return i18n( "Sender declines this task" );
01197 case Attendee::Delegated: {
01198 QString delegate, dummy;
01199 KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
01200 if ( delegate.isEmpty() ) {
01201 delegate = attendee->delegate();
01202 }
01203 if ( !delegate.isEmpty() ) {
01204 return i18n( "Sender has delegated this request for the task to %1" ).arg( delegate );
01205 } else {
01206 return i18n( "Sender has delegated this request for the task " );
01207 }
01208 }
01209 case Attendee::Completed:
01210 return i18n( "The request for this task is now completed" );
01211 case Attendee::InProcess:
01212 return i18n( "Sender is still processing the invitation" );
01213 default:
01214 return i18n( "Unknown response to this task" );
01215 }
01216 break; }
01217 case Scheduler::Counter:
01218 return i18n( "Sender makes this counter proposal" );
01219 case Scheduler::Declinecounter:
01220 return i18n( "Sender declines the counter proposal" );
01221 case Scheduler::NoMethod:
01222 return i18n("Error: iMIP message with unknown method: '%1'").
01223 arg( msg->method() );
01224 }
01225 return QString::null;
01226 }
01227
01228 static QString invitationHeaderJournal( Journal *journal, ScheduleMessage *msg )
01229 {
01230
01231 if ( !msg || !journal ) {
01232 return QString::null;
01233 }
01234
01235 switch ( msg->method() ) {
01236 case Scheduler::Publish:
01237 return i18n("This journal has been published");
01238 case Scheduler::Request:
01239 return i18n( "You have been assigned this journal" );
01240 case Scheduler::Refresh:
01241 return i18n( "This journal was refreshed" );
01242 case Scheduler::Cancel:
01243 return i18n( "This journal was canceled" );
01244 case Scheduler::Add:
01245 return i18n( "Addition to the journal" );
01246 case Scheduler::Reply: {
01247 Attendee::List attendees = journal->attendees();
01248 if( attendees.count() == 0 ) {
01249 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
01250 return QString::null;
01251 }
01252 if( attendees.count() != 1 ) {
01253 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
01254 << "but is " << attendees.count() << endl;
01255 }
01256 Attendee* attendee = *attendees.begin();
01257
01258 switch( attendee->status() ) {
01259 case Attendee::NeedsAction:
01260 return i18n( "Sender indicates this journal assignment still needs some action" );
01261 case Attendee::Accepted:
01262 return i18n( "Sender accepts this journal" );
01263 case Attendee::Tentative:
01264 return i18n( "Sender tentatively accepts this journal" );
01265 case Attendee::Declined:
01266 return i18n( "Sender declines this journal" );
01267 case Attendee::Delegated:
01268 return i18n( "Sender has delegated this request for the journal" );
01269 case Attendee::Completed:
01270 return i18n( "The request for this journal is now completed" );
01271 case Attendee::InProcess:
01272 return i18n( "Sender is still processing the invitation" );
01273 default:
01274 return i18n( "Unknown response to this journal" );
01275 }
01276 break;
01277 }
01278 case Scheduler::Counter:
01279 return i18n( "Sender makes this counter proposal" );
01280 case Scheduler::Declinecounter:
01281 return i18n( "Sender declines the counter proposal" );
01282 case Scheduler::NoMethod:
01283 return i18n("Error: iMIP message with unknown method: '%1'").
01284 arg( msg->method() );
01285 }
01286 return QString::null;
01287 }
01288
01289 static QString invitationHeaderFreeBusy( FreeBusy *fb, ScheduleMessage *msg )
01290 {
01291 if ( !msg || !fb ) {
01292 return QString::null;
01293 }
01294
01295 switch ( msg->method() ) {
01296 case Scheduler::Publish:
01297 return i18n("This free/busy list has been published");
01298 case Scheduler::Request:
01299 return i18n( "The free/busy list has been requested" );
01300 case Scheduler::Refresh:
01301 return i18n( "This free/busy list was refreshed" );
01302 case Scheduler::Cancel:
01303 return i18n( "This free/busy list was canceled" );
01304 case Scheduler::Add:
01305 return i18n( "Addition to the free/busy list" );
01306 case Scheduler::NoMethod:
01307 default:
01308 return i18n("Error: Free/Busy iMIP message with unknown method: '%1'").
01309 arg( msg->method() );
01310 }
01311 }
01312
01313 static QString invitationAttendees( Incidence *incidence )
01314 {
01315 QString tmpStr;
01316 if ( !incidence ) {
01317 return tmpStr;
01318 }
01319
01320 tmpStr += eventViewerAddTag( "u", i18n( "Attendee List" ) );
01321 tmpStr += "<br/>";
01322
01323 int count=0;
01324 Attendee::List attendees = incidence->attendees();
01325 if ( !attendees.isEmpty() ) {
01326
01327 Attendee::List::ConstIterator it;
01328 for( it = attendees.begin(); it != attendees.end(); ++it ) {
01329 Attendee *a = *it;
01330 if ( !iamAttendee( a ) ) {
01331 count++;
01332 if ( count == 1 ) {
01333 tmpStr += "<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\" columns=\"2\">";
01334 }
01335 tmpStr += "<tr>";
01336 tmpStr += "<td>";
01337 tmpStr += invitationPerson( a->email(), a->name(), QString::null );
01338 if ( !a->delegator().isEmpty() ) {
01339 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
01340 }
01341 if ( !a->delegate().isEmpty() ) {
01342 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
01343 }
01344 tmpStr += "</td>";
01345 tmpStr += "<td>" + a->statusStr() + "</td>";
01346 tmpStr += "</tr>";
01347 }
01348 }
01349 }
01350 if ( count ) {
01351 tmpStr += "</table>";
01352 } else {
01353 tmpStr += "<i>" + i18n( "No attendee", "None" ) + "</i>";
01354 }
01355
01356 return tmpStr;
01357 }
01358
01359 static QString invitationAttachments( InvitationFormatterHelper *helper, Incidence *incidence )
01360 {
01361 QString tmpStr;
01362 if ( !incidence ) {
01363 return tmpStr;
01364 }
01365
01366 Attachment::List attachments = incidence->attachments();
01367 if ( !attachments.isEmpty() ) {
01368 tmpStr += i18n( "Attached Documents:" ) + "<ol>";
01369
01370 Attachment::List::ConstIterator it;
01371 for( it = attachments.begin(); it != attachments.end(); ++it ) {
01372 Attachment *a = *it;
01373 tmpStr += "<li>";
01374
01375 KMimeType::Ptr mimeType = KMimeType::mimeType( a->mimeType() );
01376 QString iconStr = mimeType->icon( a->uri(), false );
01377 QString iconPath = KGlobal::iconLoader()->iconPath( iconStr, KIcon::Small );
01378 if ( !iconPath.isEmpty() ) {
01379 tmpStr += "<img src=\"" + iconPath + "\" align=\"top\">";
01380 }
01381 tmpStr += helper->makeLink( "ATTACH:" + a->label(), a->label() );
01382 tmpStr += "</li>";
01383 }
01384 tmpStr += "</ol>";
01385 }
01386
01387 return tmpStr;
01388 }
01389
01390 class IncidenceFormatter::ScheduleMessageVisitor : public IncidenceBase::Visitor
01391 {
01392 public:
01393 ScheduleMessageVisitor() : mMessage(0) { mResult = ""; }
01394 bool act( IncidenceBase *incidence, ScheduleMessage *msg ) { mMessage = msg; return incidence->accept( *this ); }
01395 QString result() const { return mResult; }
01396
01397 protected:
01398 QString mResult;
01399 ScheduleMessage *mMessage;
01400 };
01401
01402 class IncidenceFormatter::InvitationHeaderVisitor :
01403 public IncidenceFormatter::ScheduleMessageVisitor
01404 {
01405 protected:
01406 bool visit( Event *event )
01407 {
01408 mResult = invitationHeaderEvent( event, mMessage );
01409 return !mResult.isEmpty();
01410 }
01411 bool visit( Todo *todo )
01412 {
01413 mResult = invitationHeaderTodo( todo, mMessage );
01414 return !mResult.isEmpty();
01415 }
01416 bool visit( Journal *journal )
01417 {
01418 mResult = invitationHeaderJournal( journal, mMessage );
01419 return !mResult.isEmpty();
01420 }
01421 bool visit( FreeBusy *fb )
01422 {
01423 mResult = invitationHeaderFreeBusy( fb, mMessage );
01424 return !mResult.isEmpty();
01425 }
01426 };
01427
01428 class IncidenceFormatter::InvitationBodyVisitor :
01429 public IncidenceFormatter::ScheduleMessageVisitor
01430 {
01431 protected:
01432 bool visit( Event *event )
01433 {
01434 mResult = invitationDetailsEvent( event );
01435 return !mResult.isEmpty();
01436 }
01437 bool visit( Todo *todo )
01438 {
01439 mResult = invitationDetailsTodo( todo );
01440 return !mResult.isEmpty();
01441 }
01442 bool visit( Journal *journal )
01443 {
01444 mResult = invitationDetailsJournal( journal );
01445 return !mResult.isEmpty();
01446 }
01447 bool visit( FreeBusy *fb )
01448 {
01449 mResult = invitationDetailsFreeBusy( fb );
01450 return !mResult.isEmpty();
01451 }
01452 };
01453
01454 class IncidenceFormatter::IncidenceCompareVisitor :
01455 public IncidenceBase::Visitor
01456 {
01457 public:
01458 IncidenceCompareVisitor() : mExistingIncidence(0) {}
01459 bool act( IncidenceBase *incidence, Incidence* existingIncidence )
01460 {
01461 Incidence *inc = dynamic_cast<Incidence*>( incidence );
01462 if ( !inc || !existingIncidence || inc->revision() <= existingIncidence->revision() )
01463 return false;
01464 mExistingIncidence = existingIncidence;
01465 return incidence->accept( *this );
01466 }
01467
01468 QString result() const
01469 {
01470 if ( mChanges.isEmpty() )
01471 return QString();
01472 QString html = "<div align=\"left\"><ul><li>";
01473 html += mChanges.join( "</li><li>" );
01474 html += "</li><ul></div>";
01475 return html;
01476 }
01477
01478 protected:
01479 bool visit( Event *event )
01480 {
01481 compareEvents( event, dynamic_cast<Event*>( mExistingIncidence ) );
01482 compareIncidences( event, mExistingIncidence );
01483 return !mChanges.isEmpty();
01484 }
01485 bool visit( Todo *todo )
01486 {
01487 compareIncidences( todo, mExistingIncidence );
01488 return !mChanges.isEmpty();
01489 }
01490 bool visit( Journal *journal )
01491 {
01492 compareIncidences( journal, mExistingIncidence );
01493 return !mChanges.isEmpty();
01494 }
01495 bool visit( FreeBusy *fb )
01496 {
01497 Q_UNUSED( fb );
01498 return !mChanges.isEmpty();
01499 }
01500
01501 private:
01502 void compareEvents( Event *newEvent, Event *oldEvent )
01503 {
01504 if ( !oldEvent || !newEvent )
01505 return;
01506 if ( oldEvent->dtStart() != newEvent->dtStart() || oldEvent->doesFloat() != newEvent->doesFloat() )
01507 mChanges += i18n( "The invitation starting time has been changed from %1 to %2" )
01508 .arg( eventStartTimeStr( oldEvent ) ).arg( eventStartTimeStr( newEvent ) );
01509 if ( oldEvent->dtEnd() != newEvent->dtEnd() || oldEvent->doesFloat() != newEvent->doesFloat() )
01510 mChanges += i18n( "The invitation ending time has been changed from %1 to %2" )
01511 .arg( eventEndTimeStr( oldEvent ) ).arg( eventEndTimeStr( newEvent ) );
01512 }
01513
01514 void compareIncidences( Incidence *newInc, Incidence *oldInc )
01515 {
01516 if ( !oldInc || !newInc )
01517 return;
01518 if ( oldInc->summary() != newInc->summary() )
01519 mChanges += i18n( "The summary has been changed to: \"%1\"" ).arg( newInc->summary() );
01520 if ( oldInc->location() != newInc->location() )
01521 mChanges += i18n( "The location has been changed to: \"%1\"" ).arg( newInc->location() );
01522 if ( oldInc->description() != newInc->description() )
01523 mChanges += i18n( "The description has been changed to: \"%1\"" ).arg( newInc->description() );
01524 Attendee::List oldAttendees = oldInc->attendees();
01525 Attendee::List newAttendees = newInc->attendees();
01526 for ( Attendee::List::ConstIterator it = newAttendees.constBegin(); it != newAttendees.constEnd(); ++it ) {
01527 Attendee *oldAtt = oldInc->attendeeByMail( (*it)->email() );
01528 if ( !oldAtt ) {
01529 mChanges += i18n( "Attendee %1 has been added" ).arg( (*it)->fullName() );
01530 } else {
01531 if ( oldAtt->status() != (*it)->status() )
01532 mChanges += i18n( "The status of attendee %1 has been changed to: %2" ).arg( (*it)->fullName() )
01533 .arg( (*it)->statusStr() );
01534 }
01535 }
01536 for ( Attendee::List::ConstIterator it = oldAttendees.constBegin(); it != oldAttendees.constEnd(); ++it ) {
01537 Attendee *newAtt = newInc->attendeeByMail( (*it)->email() );
01538 if ( !newAtt )
01539 mChanges += i18n( "Attendee %1 has been removed" ).arg( (*it)->fullName() );
01540 }
01541 }
01542
01543 private:
01544 Incidence* mExistingIncidence;
01545 QStringList mChanges;
01546 };
01547
01548
01549 QString InvitationFormatterHelper::makeLink( const QString &id, const QString &text )
01550 {
01551 if ( !id.startsWith( "ATTACH:" ) ) {
01552 QString res( "<a href=\"%1\"><b>%2</b></a>" );
01553 return res.arg( generateLinkURL( id ) ).arg( text );
01554 } else {
01555
01556 QString res( "<a href=\"%1\">%2</a>" );
01557 return res.arg( generateLinkURL( id ) ).arg( text );
01558 }
01559 }
01560
01561
01562
01563 static bool incidenceOwnedByMe( Calendar *calendar, Incidence *incidence )
01564 {
01565 CalendarResources *cal = dynamic_cast<CalendarResources*>( calendar );
01566 if ( !cal || !incidence ) {
01567 return true;
01568 }
01569 ResourceCalendar *res = cal->resource( incidence );
01570 if ( !res ) {
01571 return true;
01572 }
01573 const QString subRes = res->subresourceIdentifier( incidence );
01574 if ( !subRes.contains( "/.INBOX.directory/" ) ) {
01575 return false;
01576 }
01577 return true;
01578 }
01579
01580 QString IncidenceFormatter::formatICalInvitation( QString invitation, Calendar *mCalendar,
01581 InvitationFormatterHelper *helper )
01582 {
01583 if ( invitation.isEmpty() ) return QString::null;
01584
01585 ICalFormat format;
01586
01587 ScheduleMessage *msg = format.parseScheduleMessage( mCalendar, invitation );
01588
01589 if( !msg ) {
01590 kdDebug( 5850 ) << "Failed to parse the scheduling message" << endl;
01591 Q_ASSERT( format.exception() );
01592 kdDebug( 5850 ) << format.exception()->message() << endl;
01593 return QString::null;
01594 }
01595
01596 IncidenceBase *incBase = msg->event();
01597
01598
01599 Incidence *existingIncidence = 0;
01600 if ( incBase && helper->calendar() ) {
01601 existingIncidence = helper->calendar()->incidence( incBase->uid() );
01602 if ( !incidenceOwnedByMe( helper->calendar(), existingIncidence ) ) {
01603 existingIncidence = 0;
01604 }
01605 if ( !existingIncidence ) {
01606 const Incidence::List list = helper->calendar()->incidences();
01607 for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
01608 if ( (*it)->schedulingID() == incBase->uid() &&
01609 incidenceOwnedByMe( helper->calendar(), *it ) ) {
01610 existingIncidence = *it;
01611 break;
01612 }
01613 }
01614 }
01615 }
01616
01617
01618 QString html;
01619
01620 QString tableStyle = QString::fromLatin1(
01621 "style=\"border: solid 1px; margin: 0em;\"" );
01622 QString tableHead = QString::fromLatin1(
01623 "<div align=\"center\">"
01624 "<table width=\"80%\" cellpadding=\"1\" cellspacing=\"0\" %1>"
01625 "<tr><td>").arg(tableStyle);
01626
01627 html += tableHead;
01628 InvitationHeaderVisitor headerVisitor;
01629
01630 if ( !headerVisitor.act( incBase, msg ) )
01631 return QString::null;
01632 html += "<b>" + headerVisitor.result() + "</b>";
01633
01634 InvitationBodyVisitor bodyVisitor;
01635 if ( !bodyVisitor.act( incBase, msg ) )
01636 return QString::null;
01637 html += bodyVisitor.result();
01638
01639 if ( msg->method() == Scheduler::Request ) {
01640 IncidenceCompareVisitor compareVisitor;
01641 if ( compareVisitor.act( incBase, existingIncidence ) ) {
01642 html += i18n("<p align=\"left\">The following changes have been made by the organizer:</p>");
01643 html += compareVisitor.result();
01644 }
01645 }
01646
01647 Incidence *inc = dynamic_cast<Incidence*>( incBase );
01648
01649
01650 bool myInc = iamOrganizer( inc );
01651
01652
01653 bool rsvpRec = false;
01654 Attendee *ea = 0;
01655 if ( !myInc ) {
01656 if ( existingIncidence ) {
01657 ea = findMyAttendee( existingIncidence );
01658 }
01659 if ( ea && ( ea->status() == Attendee::Accepted || ea->status() == Attendee::Declined ) ) {
01660 rsvpRec = true;
01661 }
01662 }
01663
01664
01665 bool rsvpReq = rsvpRequested( inc );
01666 if ( !myInc ) {
01667 html += "<br/>";
01668 html += "<i><u>";
01669 if ( rsvpRec && ( inc && inc->revision() == 0 ) ) {
01670 html += i18n( "Your response has already been recorded [%1]" ).
01671 arg( ea->statusStr() );
01672 rsvpReq = false;
01673 } else if ( msg->method() == Scheduler::Cancel ) {
01674 html += i18n( "This invitation was declined" );
01675 } else if ( msg->method() == Scheduler::Add ) {
01676 html += i18n( "This invitation was accepted" );
01677 } else {
01678 html += rsvpRequestedStr( rsvpReq );
01679 }
01680 html += "</u></i><br>";
01681 }
01682
01683
01684
01685 html += "<table border=\"0\" cellspacing=\"0\"><tr><td> </td></tr><tr>";
01686
01687 switch ( msg->method() ) {
01688 case Scheduler::Publish:
01689 case Scheduler::Request:
01690 case Scheduler::Refresh:
01691 case Scheduler::Add:
01692 {
01693 if ( inc && inc->revision() > 0 && ( existingIncidence || !helper->calendar() ) ) {
01694 if ( inc->type() == "Todo" ) {
01695 html += "<td colspan=\"9\">";
01696 html += helper->makeLink( "reply", i18n( "[Record invitation to my task list]" ) );
01697 } else {
01698 html += "<td colspan=\"13\">";
01699 html += helper->makeLink( "reply", i18n( "[Record invitation to my calendar]" ) );
01700 }
01701 html += "</td></tr><tr>";
01702 }
01703 html += "<td>";
01704
01705 if ( !myInc ) {
01706 if ( rsvpReq ) {
01707
01708 html += helper->makeLink( "accept", i18n( "[Accept]" ) );
01709 html += "</td><td> </td><td>";
01710 html += helper->makeLink( "accept_conditionally",
01711 i18n( "Accept conditionally", "[Accept cond.]" ) );
01712 html += "</td><td> </td><td>";
01713 }
01714
01715 if ( rsvpReq ) {
01716
01717 html += helper->makeLink( "counter", i18n( "[Counter proposal]" ) );
01718 html += "</td><td> </td><td>";
01719 }
01720
01721 if ( rsvpReq ) {
01722
01723 html += helper->makeLink( "decline", i18n( "[Decline]" ) );
01724 html += "</td><td> </td><td>";
01725 }
01726
01727 if ( !rsvpRec || ( inc && inc->revision() > 0 ) ) {
01728
01729 html += helper->makeLink( "delegate", i18n( "[Delegate]" ) );
01730 html += "</td><td> </td><td>";
01731
01732
01733 html += helper->makeLink( "forward", i18n( "[Forward]" ) );
01734
01735
01736 if ( inc && inc->type() == "Event" ) {
01737 html += "</td><td> </td><td>";
01738 html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
01739 }
01740 }
01741 }
01742 break;
01743 }
01744
01745 case Scheduler::Cancel:
01746
01747 if ( inc->type() == "Todo" ) {
01748 html += helper->makeLink( "cancel", i18n( "[Remove invitation from my task list]" ) );
01749 } else {
01750 html += helper->makeLink( "cancel", i18n( "[Remove invitation from my calendar]" ) );
01751 }
01752 break;
01753
01754 case Scheduler::Reply:
01755 {
01756
01757 Attendee *a = 0;
01758 Attendee *ea = 0;
01759 if ( inc ) {
01760 a = inc->attendees().first();
01761 if ( a ) {
01762 ea = findAttendee( existingIncidence, a->email() );
01763 }
01764 }
01765 if ( ea && ( ea->status() != Attendee::NeedsAction ) && ( ea->status() == a->status() ) ) {
01766 if ( inc && inc->revision() > 0 ) {
01767 html += "<br><u><i>";
01768 html += i18n( "The response has been recorded [%1]" ).arg( ea->statusStr() );
01769 html += "</i></u>";
01770 }
01771 } else {
01772 if ( inc ) {
01773 if ( inc->type() == "Todo" ) {
01774 html += helper->makeLink( "reply", i18n( "[Record response into my task list]" ) );
01775 } else {
01776 html += helper->makeLink( "reply", i18n( "[Record response into my calendar]" ) );
01777 }
01778 }
01779 }
01780 break;
01781 }
01782
01783 case Scheduler::Counter:
01784
01785 html += helper->makeLink( "accept_counter", i18n("[Accept]") );
01786 html += " ";
01787 html += helper->makeLink( "decline_counter", i18n("[Decline]") );
01788 html += " ";
01789 html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
01790 break;
01791
01792 case Scheduler::Declinecounter:
01793 case Scheduler::NoMethod:
01794 break;
01795 }
01796
01797
01798 html += "</td></tr></table>";
01799
01800
01801 if ( myInc && helper->calendar() ) {
01802 html += invitationAttendees( helper->calendar()->incidence( inc->uid() ) );
01803 }
01804
01805
01806 html += "</td></tr></table><br></div>";
01807
01808
01809 html += invitationAttachments( helper, inc );
01810
01811 return html;
01812 }
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824 static QString stringProp( KTNEFMessage* tnefMsg, const Q_UINT32& key,
01825 const QString& fallback = QString::null)
01826 {
01827 return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16,
01828 fallback );
01829 }
01830
01831 static QString sNamedProp( KTNEFMessage* tnefMsg, const QString& name,
01832 const QString& fallback = QString::null )
01833 {
01834 return tnefMsg->findNamedProp( name, fallback );
01835 }
01836
01837 struct save_tz { char* old_tz; char* tz_env_str; };
01838
01839
01840 static struct save_tz set_tz( const char* _tc )
01841 {
01842 const char *tc = _tc?_tc:"UTC";
01843
01844 struct save_tz rv;
01845
01846 rv.old_tz = 0;
01847 rv.tz_env_str = 0;
01848
01849
01850
01851 char* tz_env = 0;
01852 if( getenv( "TZ" ) ) {
01853 tz_env = strdup( getenv( "TZ" ) );
01854 rv.old_tz = tz_env;
01855 }
01856 char* tmp_env = (char*)malloc( strlen( tc ) + 4 );
01857 strcpy( tmp_env, "TZ=" );
01858 strcpy( tmp_env+3, tc );
01859 putenv( tmp_env );
01860
01861 rv.tz_env_str = tmp_env;
01862
01863
01864
01865 tzset();
01866
01867
01868 return rv;
01869 }
01870
01871
01872 static void unset_tz( struct save_tz old_tz )
01873 {
01874 if( old_tz.old_tz ) {
01875 char* tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 );
01876 strcpy( tmp_env, "TZ=" );
01877 strcpy( tmp_env+3, old_tz.old_tz );
01878 putenv( tmp_env );
01879
01880 free( old_tz.old_tz );
01881 } else {
01882
01883 putenv( strdup("TZ") );
01884 }
01885 tzset();
01886
01887
01888 if( old_tz.tz_env_str ) free( old_tz.tz_env_str );
01889 }
01890
01891 static QDateTime utc2Local( const QDateTime& utcdt )
01892 {
01893 struct tm tmL;
01894
01895 save_tz tmp_tz = set_tz("UTC");
01896 time_t utc = utcdt.toTime_t();
01897 unset_tz( tmp_tz );
01898
01899 localtime_r( &utc, &tmL );
01900 return QDateTime( QDate( tmL.tm_year+1900, tmL.tm_mon+1, tmL.tm_mday ),
01901 QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
01902 }
01903
01904
01905 static QDateTime pureISOToLocalQDateTime( const QString& dtStr,
01906 bool bDateOnly = false )
01907 {
01908 QDate tmpDate;
01909 QTime tmpTime;
01910 int year, month, day, hour, minute, second;
01911
01912 if( bDateOnly ) {
01913 year = dtStr.left( 4 ).toInt();
01914 month = dtStr.mid( 4, 2 ).toInt();
01915 day = dtStr.mid( 6, 2 ).toInt();
01916 hour = 0;
01917 minute = 0;
01918 second = 0;
01919 } else {
01920 year = dtStr.left( 4 ).toInt();
01921 month = dtStr.mid( 4, 2 ).toInt();
01922 day = dtStr.mid( 6, 2 ).toInt();
01923 hour = dtStr.mid( 9, 2 ).toInt();
01924 minute = dtStr.mid( 11, 2 ).toInt();
01925 second = dtStr.mid( 13, 2 ).toInt();
01926 }
01927 tmpDate.setYMD( year, month, day );
01928 tmpTime.setHMS( hour, minute, second );
01929
01930 if( tmpDate.isValid() && tmpTime.isValid() ) {
01931 QDateTime dT = QDateTime( tmpDate, tmpTime );
01932
01933 if( !bDateOnly ) {
01934
01935 if (dtStr.at(dtStr.length()-1) == 'Z') {
01936
01937
01938 dT = utc2Local( dT );
01939 }
01940 }
01941 return dT;
01942 } else
01943 return QDateTime();
01944 }
01945
01946
01947
01948 QString IncidenceFormatter::msTNEFToVPart( const QByteArray& tnef )
01949 {
01950 bool bOk = false;
01951
01952 KTNEFParser parser;
01953 QBuffer buf( tnef );
01954 CalendarLocal cal ( QString::fromLatin1( "UTC" ) );
01955 KABC::Addressee addressee;
01956 KABC::VCardConverter cardConv;
01957 ICalFormat calFormat;
01958 Event* event = new Event();
01959
01960 if( parser.openDevice( &buf ) ) {
01961 KTNEFMessage* tnefMsg = parser.message();
01962
01963
01964
01965
01966 QString msgClass = tnefMsg->findProp( 0x001A, QString::null, true )
01967 .upper();
01968 if( !msgClass.isEmpty() ) {
01969
01970
01971 bool bCompatClassAppointment = false;
01972 bool bCompatMethodRequest = false;
01973 bool bCompatMethodCancled = false;
01974 bool bCompatMethodAccepted = false;
01975 bool bCompatMethodAcceptedCond = false;
01976 bool bCompatMethodDeclined = false;
01977 if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ) {
01978 bCompatClassAppointment = true;
01979 if( msgClass.endsWith( ".MTGREQ" ) )
01980 bCompatMethodRequest = true;
01981 if( msgClass.endsWith( ".MTGCNCL" ) )
01982 bCompatMethodCancled = true;
01983 if( msgClass.endsWith( ".MTGRESPP" ) )
01984 bCompatMethodAccepted = true;
01985 if( msgClass.endsWith( ".MTGRESPA" ) )
01986 bCompatMethodAcceptedCond = true;
01987 if( msgClass.endsWith( ".MTGRESPN" ) )
01988 bCompatMethodDeclined = true;
01989 }
01990 bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" );
01991
01992 if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) {
01993
01994 bool bIsReply = false;
01995 QString prodID = "-//Microsoft Corporation//Outlook ";
01996 prodID += tnefMsg->findNamedProp( "0x8554", "9.0" );
01997 prodID += "MIMEDIR/EN\n";
01998 prodID += "VERSION:2.0\n";
01999 calFormat.setApplication( "Outlook", prodID );
02000
02001 Scheduler::Method method;
02002 if( bCompatMethodRequest )
02003 method = Scheduler::Request;
02004 else if( bCompatMethodCancled )
02005 method = Scheduler::Cancel;
02006 else if( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
02007 bCompatMethodDeclined ) {
02008 method = Scheduler::Reply;
02009 bIsReply = true;
02010 } else {
02011
02012
02013
02014
02015
02016
02017
02018
02019 if( tnefMsg->findProp(0x0c17) == "1" )
02020 bIsReply = true;
02021 method = Scheduler::Request;
02022 }
02023
02025 ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown );
02026
02027 QString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) );
02028
02029 if( !sSenderSearchKeyEmail.isEmpty() ) {
02030 int colon = sSenderSearchKeyEmail.find( ':' );
02031
02032 if( sSenderSearchKeyEmail.find( ':' ) == -1 )
02033 sSenderSearchKeyEmail.remove( 0, colon+1 );
02034 }
02035
02036 QString s( tnefMsg->findProp( 0x0e04 ) );
02037 QStringList attendees = QStringList::split( ';', s );
02038 if( attendees.count() ) {
02039 for( QStringList::Iterator it = attendees.begin();
02040 it != attendees.end(); ++it ) {
02041
02042
02043 if( (*it).find('@') == -1 ) {
02044 s = (*it).stripWhiteSpace();
02045
02046 Attendee *attendee = new Attendee( s, s, true );
02047 if( bIsReply ) {
02048 if( bCompatMethodAccepted )
02049 attendee->setStatus( Attendee::Accepted );
02050 if( bCompatMethodDeclined )
02051 attendee->setStatus( Attendee::Declined );
02052 if( bCompatMethodAcceptedCond )
02053 attendee->setStatus(Attendee::Tentative);
02054 } else {
02055 attendee->setStatus( Attendee::NeedsAction );
02056 attendee->setRole( Attendee::ReqParticipant );
02057 }
02058 event->addAttendee(attendee);
02059 }
02060 }
02061 } else {
02062
02063
02064 s = sSenderSearchKeyEmail;
02065 if( !s.isEmpty() ) {
02066 Attendee *attendee = new Attendee( QString::null, QString::null,
02067 true );
02068 if( bIsReply ) {
02069 if( bCompatMethodAccepted )
02070 attendee->setStatus( Attendee::Accepted );
02071 if( bCompatMethodAcceptedCond )
02072 attendee->setStatus( Attendee::Declined );
02073 if( bCompatMethodDeclined )
02074 attendee->setStatus( Attendee::Tentative );
02075 } else {
02076 attendee->setStatus(Attendee::NeedsAction);
02077 attendee->setRole(Attendee::ReqParticipant);
02078 }
02079 event->addAttendee(attendee);
02080 }
02081 }
02082 s = tnefMsg->findProp( 0x0c1f );
02083 if( s.isEmpty() && !bIsReply )
02084 s = sSenderSearchKeyEmail;
02085
02086 if( !s.isEmpty() )
02087 event->setOrganizer( s );
02088
02089 s = tnefMsg->findProp( 0x8516 ).replace( QChar( '-' ), QString::null )
02090 .replace( QChar( ':' ), QString::null );
02091 event->setDtStart( QDateTime::fromString( s ) );
02092
02093 s = tnefMsg->findProp( 0x8517 ).replace( QChar( '-' ), QString::null )
02094 .replace( QChar( ':' ), QString::null );
02095 event->setDtEnd( QDateTime::fromString( s ) );
02096
02097 s = tnefMsg->findProp( 0x8208 );
02098 event->setLocation( s );
02099
02100
02101
02102
02103
02104
02105 s = tnefMsg->findProp( 0x0023 );
02106 event->setUid( s );
02107
02108
02109
02110
02111 s = tnefMsg->findProp( 0x8202 ).replace( QChar( '-' ), QString::null )
02112 .replace( QChar( ':' ), QString::null );
02113
02114
02115
02116 s = tnefMsg->findNamedProp( "Keywords" );
02117 event->setCategories( s );
02118
02119 s = tnefMsg->findProp( 0x1000 );
02120 event->setDescription( s );
02121
02122 s = tnefMsg->findProp( 0x0070 );
02123 event->setSummary( s );
02124
02125 s = tnefMsg->findProp( 0x0026 );
02126 event->setPriority( s.toInt() );
02127
02128
02129 if(!tnefMsg->findProp(0x8503).isEmpty()) {
02130 Alarm *alarm = new Alarm(event);
02131 QDateTime highNoonTime =
02132 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8502 )
02133 .replace( QChar( '-' ), "" )
02134 .replace( QChar( ':' ), "" ) );
02135 QDateTime wakeMeUpTime =
02136 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8560, "" )
02137 .replace( QChar( '-' ), "" )
02138 .replace( QChar( ':' ), "" ) );
02139 alarm->setTime(wakeMeUpTime);
02140
02141 if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
02142 alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
02143 else
02144
02145 alarm->setStartOffset( Duration( 15*60 ) );
02146 alarm->setDisplayAlarm( i18n( "Reminder" ) );
02147
02148
02149
02150 event->addAlarm( alarm );
02151 }
02152 cal.addEvent( event );
02153 bOk = true;
02154
02155 } else if( bCompatClassNote || "IPM.CONTACT" == msgClass ) {
02156 addressee.setUid( stringProp( tnefMsg, attMSGID ) );
02157 addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
02158 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true );
02159 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false );
02160 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false );
02161 addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
02162 addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
02163 addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
02164 addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
02165 addressee.insertCustom( "KADDRESSBOOK", "X-Department", stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
02166 addressee.insertCustom( "KADDRESSBOOK", "X-Office", stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
02167 addressee.insertCustom( "KADDRESSBOOK", "X-Profession", stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
02168
02169 QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY )
02170 .replace( QChar( '-' ), QString::null )
02171 .replace( QChar( ':' ), QString::null );
02172 if( !s.isEmpty() )
02173 addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s );
02174
02175 addressee.setUrl( KURL( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) );
02176
02177
02178 addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
02179 addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
02180 addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
02181 addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
02182 addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
02183
02184 addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
02185 addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
02186 addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
02187
02188
02189
02190
02191
02192 KABC::Address adr;
02193 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
02194 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
02195 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
02196 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
02197 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
02198 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
02199 adr.setType(KABC::Address::Home);
02200 addressee.insertAddress(adr);
02201
02202 adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
02203 adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
02204 adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
02205 adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
02206 adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
02207 adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
02208 adr.setType( KABC::Address::Work );
02209 addressee.insertAddress( adr );
02210
02211 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
02212 adr.setStreet( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
02213 adr.setLocality( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
02214 adr.setRegion( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
02215 adr.setPostalCode( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
02216 adr.setCountry( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
02217 adr.setType( KABC::Address::Dom );
02218 addressee.insertAddress(adr);
02219
02220
02221
02222
02223
02224 QString nr;
02225 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
02226 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) );
02227 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
02228 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) );
02229 nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
02230 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) );
02231 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
02232 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) );
02233 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
02234 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) );
02235
02236 s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY )
02237 .replace( QChar( '-' ), QString::null )
02238 .replace( QChar( ':' ), QString::null );
02239 if( !s.isEmpty() )
02240 addressee.setBirthday( QDateTime::fromString( s ) );
02241
02242 bOk = ( !addressee.isEmpty() );
02243 } else if( "IPM.NOTE" == msgClass ) {
02244
02245 }
02246 }
02247 }
02248
02249
02250 QString iCal = calFormat.toString( &cal );
02251 if( !iCal.isEmpty() )
02252
02253 return iCal;
02254
02255
02256 KABC::VCardConverter converter;
02257 return converter.createVCard( addressee );
02258 }
02259
02260
02261 QString IncidenceFormatter::formatTNEFInvitation( const QByteArray& tnef,
02262 Calendar *mCalendar, InvitationFormatterHelper *helper )
02263 {
02264 QString vPart = IncidenceFormatter::msTNEFToVPart( tnef );
02265 QString iCal = IncidenceFormatter::formatICalInvitation( vPart, mCalendar, helper );
02266 if( !iCal.isEmpty() )
02267 return iCal;
02268 return vPart;
02269 }
02270
02271
02272
02273
02274
02275
02276
02277
02278 class IncidenceFormatter::ToolTipVisitor : public IncidenceBase::Visitor
02279 {
02280 public:
02281 ToolTipVisitor() : mRichText( true ), mResult( "" ) {}
02282
02283 bool act( IncidenceBase *incidence, bool richText=true)
02284 {
02285 mRichText = richText;
02286 mResult = "";
02287 return incidence ? incidence->accept( *this ) : false;
02288 }
02289 QString result() const { return mResult; }
02290
02291 protected:
02292 bool visit( Event *event );
02293 bool visit( Todo *todo );
02294 bool visit( Journal *journal );
02295 bool visit( FreeBusy *fb );
02296
02297 QString dateRangeText( Event*event );
02298 QString dateRangeText( Todo *todo );
02299 QString dateRangeText( Journal *journal );
02300 QString dateRangeText( FreeBusy *fb );
02301
02302 QString generateToolTip( Incidence* incidence, QString dtRangeText );
02303
02304 protected:
02305 bool mRichText;
02306 QString mResult;
02307 };
02308
02309 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Event*event )
02310 {
02311 QString ret;
02312 QString tmp;
02313 if ( event->isMultiDay() ) {
02314
02315 tmp = "<br>" + i18n("Event start", "<i>From:</i> %1");
02316 if (event->doesFloat())
02317 ret += tmp.arg( event->dtStartDateStr().replace(" ", " ") );
02318 else
02319 ret += tmp.arg( event->dtStartStr().replace(" ", " ") );
02320
02321 tmp = "<br>" + i18n("Event end","<i>To:</i> %1");
02322 if (event->doesFloat())
02323 ret += tmp.arg( event->dtEndDateStr().replace(" ", " ") );
02324 else
02325 ret += tmp.arg( event->dtEndStr().replace(" ", " ") );
02326
02327 } else {
02328
02329 ret += "<br>"+i18n("<i>Date:</i> %1").
02330 arg( event->dtStartDateStr().replace(" ", " ") );
02331 if ( !event->doesFloat() ) {
02332 const QString dtStartTime = event->dtStartTimeStr().replace( " ", " " );
02333 const QString dtEndTime = event->dtEndTimeStr().replace( " ", " " );
02334 if ( dtStartTime == dtEndTime ) {
02335 tmp = "<br>" + i18n("time for event, to prevent ugly line breaks",
02336 "<i>Time:</i> %1").
02337 arg( dtStartTime );
02338 } else {
02339 tmp = "<br>" + i18n("time range for event, to prevent ugly line breaks",
02340 "<i>Time:</i> %1 - %2").
02341 arg( dtStartTime, dtEndTime );
02342 }
02343 ret += tmp;
02344 }
02345
02346 }
02347 return ret;
02348 }
02349
02350 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Todo*todo )
02351 {
02352 QString ret;
02353 bool floats( todo->doesFloat() );
02354 if (todo->hasStartDate())
02355
02356
02357
02358 ret += "<br>" + i18n("<i>Start:</i> %1").arg(
02359 (floats)
02360 ?(todo->dtStartDateStr().replace(" ", " "))
02361 :(todo->dtStartStr().replace(" ", " ")) ) ;
02362 if (todo->hasDueDate())
02363 ret += "<br>" + i18n("<i>Due:</i> %1").arg(
02364 (floats)
02365 ?(todo->dtDueDateStr().replace(" ", " "))
02366 :(todo->dtDueStr().replace(" ", " ")) );
02367 if (todo->isCompleted())
02368 ret += "<br>" + i18n("<i>Completed:</i> %1").arg( todo->completedStr().replace(" ", " ") );
02369 else
02370 ret += "<br>" + i18n("%1 % completed").arg(todo->percentComplete());
02371
02372 return ret;
02373 }
02374
02375 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Journal*journal )
02376 {
02377 QString ret;
02378 if (journal->dtStart().isValid() ) {
02379 ret += "<br>" + i18n("<i>Date:</i> %1").arg( journal->dtStartDateStr( false ) );
02380 }
02381 return ret;
02382 }
02383
02384 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( FreeBusy *fb )
02385 {
02386 QString tmp( "<br>" + i18n("<i>Period start:</i> %1") );
02387 QString ret = tmp.arg( KGlobal::locale()->formatDateTime( fb->dtStart() ) );
02388 tmp = "<br>" + i18n("<i>Period start:</i> %1");
02389 ret += tmp.arg( KGlobal::locale()->formatDateTime( fb->dtEnd() ) );
02390 return ret;
02391 }
02392
02393
02394
02395 bool IncidenceFormatter::ToolTipVisitor::visit( Event *event )
02396 {
02397 mResult = generateToolTip( event, dateRangeText( event ) );
02398 return !mResult.isEmpty();
02399 }
02400
02401 bool IncidenceFormatter::ToolTipVisitor::visit( Todo *todo )
02402 {
02403 mResult = generateToolTip( todo, dateRangeText( todo ) );
02404 return !mResult.isEmpty();
02405 }
02406
02407 bool IncidenceFormatter::ToolTipVisitor::visit( Journal *journal )
02408 {
02409 mResult = generateToolTip( journal, dateRangeText( journal ) );
02410 return !mResult.isEmpty();
02411 }
02412
02413 bool IncidenceFormatter::ToolTipVisitor::visit( FreeBusy *fb )
02414 {
02415 mResult = "<qt><b>" + i18n("Free/Busy information for %1")
02416 .arg(fb->organizer().fullName()) + "</b>";
02417 mResult += dateRangeText( fb );
02418 mResult += "</qt>";
02419 return !mResult.isEmpty();
02420 }
02421
02422 QString IncidenceFormatter::ToolTipVisitor::generateToolTip( Incidence* incidence, QString dtRangeText )
02423 {
02424 if ( !incidence )
02425 return QString::null;
02426
02427 QString tmp = "<qt><b>"+ incidence->summary().replace("\n", "<br>")+"</b>";
02428
02429 tmp += dtRangeText;
02430
02431 if (!incidence->location().isEmpty()) {
02432
02433 tmp += "<br>"+i18n("<i>Location:</i> %1").
02434 arg( incidence->location().replace("\n", "<br>") );
02435 }
02436 if (!incidence->description().isEmpty()) {
02437 QString desc(incidence->description());
02438 if (desc.length()>120) {
02439 desc = desc.left(120) + "...";
02440 }
02441 tmp += "<br>----------<br>" + i18n("<i>Description:</i><br>") + desc.replace("\n", "<br>");
02442 }
02443 tmp += "</qt>";
02444 return tmp;
02445 }
02446
02447 QString IncidenceFormatter::toolTipString( IncidenceBase *incidence, bool richText )
02448 {
02449 ToolTipVisitor v;
02450 if ( v.act( incidence, richText ) ) {
02451 return v.result();
02452 } else
02453 return QString::null;
02454 }
02455
02456
02457
02458
02459
02460
02461
02462
02463 class IncidenceFormatter::MailBodyVisitor : public IncidenceBase::Visitor
02464 {
02465 public:
02466 MailBodyVisitor() : mResult( "" ) {}
02467
02468 bool act( IncidenceBase *incidence )
02469 {
02470 mResult = "";
02471 return incidence ? incidence->accept( *this ) : false;
02472 }
02473 QString result() const { return mResult; }
02474
02475 protected:
02476 bool visit( Event *event );
02477 bool visit( Todo *todo );
02478 bool visit( Journal *journal );
02479 bool visit( FreeBusy * ) { mResult = i18n("This is a Free Busy Object"); return !mResult.isEmpty(); }
02480 protected:
02481 QString mResult;
02482 };
02483
02484
02485 static QString mailBodyIncidence( Incidence *incidence )
02486 {
02487 QString body;
02488 if ( !incidence->summary().isEmpty() ) {
02489 body += i18n("Summary: %1\n").arg( incidence->summary() );
02490 }
02491 if ( !incidence->organizer().isEmpty() ) {
02492 body += i18n("Organizer: %1\n").arg( incidence->organizer().fullName() );
02493 }
02494 if ( !incidence->location().isEmpty() ) {
02495 body += i18n("Location: %1\n").arg( incidence->location() );
02496 }
02497 return body;
02498 }
02499
02500 bool IncidenceFormatter::MailBodyVisitor::visit( Event *event )
02501 {
02502 QString recurrence[]= {i18n("no recurrence", "None"),
02503 i18n("Minutely"), i18n("Hourly"), i18n("Daily"),
02504 i18n("Weekly"), i18n("Monthly Same Day"), i18n("Monthly Same Position"),
02505 i18n("Yearly"), i18n("Yearly"), i18n("Yearly")};
02506
02507 mResult = mailBodyIncidence( event );
02508 mResult += i18n("Start Date: %1\n").arg( event->dtStartDateStr() );
02509 if ( !event->doesFloat() ) {
02510 mResult += i18n("Start Time: %1\n").arg( event->dtStartTimeStr() );
02511 }
02512 if ( event->dtStart() != event->dtEnd() ) {
02513 mResult += i18n("End Date: %1\n").arg( event->dtEndDateStr() );
02514 }
02515 if ( !event->doesFloat() ) {
02516 mResult += i18n("End Time: %1\n").arg( event->dtEndTimeStr() );
02517 }
02518 if ( event->doesRecur() ) {
02519 Recurrence *recur = event->recurrence();
02520
02521 mResult += i18n("Recurs: %1\n")
02522 .arg( recurrence[ recur->recurrenceType() ] );
02523 mResult += i18n("Frequency: %1\n")
02524 .arg( event->recurrence()->frequency() );
02525
02526 if ( recur->duration() > 0 ) {
02527 mResult += i18n ("Repeats once", "Repeats %n times", recur->duration());
02528 mResult += '\n';
02529 } else {
02530 if ( recur->duration() != -1 ) {
02531
02532 QString endstr;
02533 if ( event->doesFloat() ) {
02534 endstr = KGlobal::locale()->formatDate( recur->endDate() );
02535 } else {
02536 endstr = KGlobal::locale()->formatDateTime( recur->endDateTime() );
02537 }
02538 mResult += i18n("Repeat until: %1\n").arg( endstr );
02539 } else {
02540 mResult += i18n("Repeats forever\n");
02541 }
02542 }
02543 }
02544 QString details = event->description();
02545 if ( !details.isEmpty() ) {
02546 mResult += i18n("Details:\n%1\n").arg( details );
02547 }
02548 return !mResult.isEmpty();
02549 }
02550
02551 bool IncidenceFormatter::MailBodyVisitor::visit( Todo *todo )
02552 {
02553 mResult = mailBodyIncidence( todo );
02554
02555 if ( todo->hasStartDate() ) {
02556 mResult += i18n("Start Date: %1\n").arg( todo->dtStartDateStr() );
02557 if ( !todo->doesFloat() ) {
02558 mResult += i18n("Start Time: %1\n").arg( todo->dtStartTimeStr() );
02559 }
02560 }
02561 if ( todo->hasDueDate() ) {
02562 mResult += i18n("Due Date: %1\n").arg( todo->dtDueDateStr() );
02563 if ( !todo->doesFloat() ) {
02564 mResult += i18n("Due Time: %1\n").arg( todo->dtDueTimeStr() );
02565 }
02566 }
02567 QString details = todo->description();
02568 if ( !details.isEmpty() ) {
02569 mResult += i18n("Details:\n%1\n").arg( details );
02570 }
02571 return !mResult.isEmpty();
02572 }
02573
02574 bool IncidenceFormatter::MailBodyVisitor::visit( Journal *journal )
02575 {
02576 mResult = mailBodyIncidence( journal );
02577 mResult += i18n("Date: %1\n").arg( journal->dtStartDateStr() );
02578 if ( !journal->doesFloat() ) {
02579 mResult += i18n("Time: %1\n").arg( journal->dtStartTimeStr() );
02580 }
02581 if ( !journal->description().isEmpty() )
02582 mResult += i18n("Text of the journal:\n%1\n").arg( journal->description() );
02583 return !mResult.isEmpty();
02584 }
02585
02586
02587
02588 QString IncidenceFormatter::mailBodyString( IncidenceBase *incidence )
02589 {
02590 if ( !incidence )
02591 return QString::null;
02592
02593 MailBodyVisitor v;
02594 if ( v.act( incidence ) ) {
02595 return v.result();
02596 }
02597 return QString::null;
02598 }
02599
02600 QString IncidenceFormatter::recurrenceString(Incidence * incidence)
02601 {
02602 if ( !incidence->doesRecur() )
02603 return i18n( "No recurrence" );
02604
02605
02606 QStringList dayList;
02607 dayList.append( i18n( "31st Last" ) );
02608 dayList.append( i18n( "30th Last" ) );
02609 dayList.append( i18n( "29th Last" ) );
02610 dayList.append( i18n( "28th Last" ) );
02611 dayList.append( i18n( "27th Last" ) );
02612 dayList.append( i18n( "26th Last" ) );
02613 dayList.append( i18n( "25th Last" ) );
02614 dayList.append( i18n( "24th Last" ) );
02615 dayList.append( i18n( "23rd Last" ) );
02616 dayList.append( i18n( "22nd Last" ) );
02617 dayList.append( i18n( "21st Last" ) );
02618 dayList.append( i18n( "20th Last" ) );
02619 dayList.append( i18n( "19th Last" ) );
02620 dayList.append( i18n( "18th Last" ) );
02621 dayList.append( i18n( "17th Last" ) );
02622 dayList.append( i18n( "16th Last" ) );
02623 dayList.append( i18n( "15th Last" ) );
02624 dayList.append( i18n( "14th Last" ) );
02625 dayList.append( i18n( "13th Last" ) );
02626 dayList.append( i18n( "12th Last" ) );
02627 dayList.append( i18n( "11th Last" ) );
02628 dayList.append( i18n( "10th Last" ) );
02629 dayList.append( i18n( "9th Last" ) );
02630 dayList.append( i18n( "8th Last" ) );
02631 dayList.append( i18n( "7th Last" ) );
02632 dayList.append( i18n( "6th Last" ) );
02633 dayList.append( i18n( "5th Last" ) );
02634 dayList.append( i18n( "4th Last" ) );
02635 dayList.append( i18n( "3rd Last" ) );
02636 dayList.append( i18n( "2nd Last" ) );
02637 dayList.append( i18n( "last day of the month", "Last" ) );
02638 dayList.append( i18n( "unknown day of the month", "unknown" ) );
02639 dayList.append( i18n( "1st" ) );
02640 dayList.append( i18n( "2nd" ) );
02641 dayList.append( i18n( "3rd" ) );
02642 dayList.append( i18n( "4th" ) );
02643 dayList.append( i18n( "5th" ) );
02644
02645 QString recurString;
02646 const KCalendarSystem *calSys = KGlobal::locale()->calendar();;
02647
02648 Recurrence *recurs = incidence->recurrence();
02649 switch ( recurs->recurrenceType() ) {
02650
02651 case Recurrence::rNone:
02652 recurString = i18n( "no recurrence", "None" );
02653 break;
02654 case Recurrence::rDaily:
02655 recurString = i18n( "Every day", "Every %1 days", recurs->frequency() );
02656 break;
02657 case Recurrence::rWeekly:
02658 {
02659 QString dayNames;
02660
02661 int weekStart = KGlobal::locale()->weekStartDay();
02662 bool addSpace = false;
02663 for ( int i = 0; i < 7; ++i ) {
02664 if ( recurs->days().testBit( (i+weekStart+6)%7 )) {
02665 if (addSpace) dayNames.append(" ");
02666 dayNames.append( calSys->weekDayName( ((i+weekStart+6)%7)+1, true ) );
02667 addSpace=true;
02668 }
02669 }
02670 recurString = i18n( "Every week on %1",
02671 "Every %n weeks on %1",
02672 recurs->frequency()).arg( dayNames );
02673 break;
02674 }
02675 case Recurrence::rMonthlyPos:
02676 {
02677 KCal::RecurrenceRule::WDayPos rule = recurs->monthPositions()[0];
02678 recurString = i18n( "Every month on the %1 %2",
02679 "Every %n months on the %1 %2",
02680 recurs->frequency() ).arg(dayList[rule.pos() + 31]).arg(
02681 calSys->weekDayName( rule.day(),false ) );
02682 break;
02683 }
02684 case Recurrence::rMonthlyDay:
02685 {
02686 int days = recurs->monthDays()[0];
02687 if (days < 0) {
02688 recurString = i18n( "Every month on the %1 day",
02689 "Every %n months on the %1 day",
02690 recurs->frequency() ).arg( dayList[days + 31] );
02691 } else {
02692 recurString = i18n( "Every month on day %1",
02693 "Every %n months on day %1",
02694 recurs->frequency() ).arg( recurs->monthDays()[0] );
02695 }
02696 break;
02697 }
02698
02699 case Recurrence::rYearlyMonth:
02700 {
02701 recurString = i18n( "Every year on day %1 of %2",
02702 "Every %n years on day %1 of %2",
02703 recurs->frequency() )
02704 .arg(recurs->yearDates()[0])
02705 .arg(calSys->monthName( recurs->yearMonths()[0], recurs->startDate().year() ) );
02706 break;
02707 }
02708 case Recurrence::rYearlyPos:
02709 {
02710 KCal::RecurrenceRule::WDayPos rule = recurs->yearPositions()[0];
02711 recurString = i18n( "Every year on the %1 %2 of %3",
02712 "Every %n years on the %1 %2of %3",
02713 recurs->frequency()).arg( dayList[rule.pos() + 31] )
02714 .arg( calSys->weekDayName( rule.day(), false ))
02715 .arg( calSys->monthName( recurs->yearMonths()[0], recurs->startDate().year() ) );
02716 break;
02717 }
02718 case Recurrence::rYearlyDay:
02719 {
02720 recurString = i18n( "Every year on day %1",
02721 "Every %n years on day %1",
02722 recurs->frequency()).arg( recurs->yearDays()[0] );
02723 break;
02724 }
02725
02726 default:
02727 return i18n( "Incidence recurs" );
02728 }
02729
02730 return recurString;
02731 }