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