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
00034 #include <libemailfunctions/email.h>
00035
00036 #include <ktnef/ktnefparser.h>
00037 #include <ktnef/ktnefmessage.h>
00038 #include <ktnef/ktnefdefs.h>
00039 #include <kabc/phonenumber.h>
00040 #include <kabc/vcardconverter.h>
00041 #include <kabc/stdaddressbook.h>
00042
00043 #include <kapplication.h>
00044
00045
00046 #include <klocale.h>
00047 #include <kglobal.h>
00048 #include <kiconloader.h>
00049
00050 #include <qbuffer.h>
00051 #include <qstylesheet.h>
00052 #include <qdatetime.h>
00053
00054 #include <time.h>
00055
00056
00057 using namespace KCal;
00058
00059
00060
00061
00062
00063
00064 static QString eventViewerAddLink( const QString &ref, const QString &text,
00065 bool newline = true )
00066 {
00067 QString tmpStr( "<a href=\"" + ref + "\">" + text + "</a>" );
00068 if ( newline ) tmpStr += "\n";
00069 return tmpStr;
00070 }
00071
00072 static QString eventViewerAddTag( const QString & tag, const QString & text )
00073 {
00074 int numLineBreaks = text.contains( "\n" );
00075 QString str = "<" + tag + ">";
00076 QString tmpText = text;
00077 QString tmpStr = str;
00078 if( numLineBreaks >= 0 ) {
00079 if ( numLineBreaks > 0) {
00080 int pos = 0;
00081 QString tmp;
00082 for( int i = 0; i <= numLineBreaks; i++ ) {
00083 pos = tmpText.find( "\n" );
00084 tmp = tmpText.left( pos );
00085 tmpText = tmpText.right( tmpText.length() - pos - 1 );
00086 tmpStr += tmp + "<br>";
00087 }
00088 } else {
00089 tmpStr += tmpText;
00090 }
00091 }
00092 tmpStr += "</" + tag + ">";
00093 return tmpStr;
00094 }
00095
00096 static QString linkPerson( const QString& email, QString name, QString uid )
00097 {
00098
00099
00100 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
00101 KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
00102 KABC::Addressee::List addressList = add_book->findByEmail( email );
00103 KABC::Addressee o = addressList.first();
00104 if ( !o.isEmpty() && addressList.size() < 2 ) {
00105 if ( name.isEmpty() )
00106
00107 name = o.formattedName();
00108 uid = o.uid();
00109 } else
00110
00111 uid = QString::null;
00112 }
00113 kdDebug(5850) << "formatAttendees: uid = " << uid << endl;
00114
00115
00116 QString tmpString = "<li>";
00117 if ( !uid.isEmpty() ) {
00118
00119 if ( name.isEmpty() )
00120
00121 tmpString += eventViewerAddLink( "uid:" + uid, email );
00122 else
00123 tmpString += eventViewerAddLink( "uid:" + uid, name );
00124 } else {
00125
00126 tmpString += ( name.isEmpty() ? email : name );
00127 }
00128 tmpString += '\n';
00129
00130
00131 if ( !email.isEmpty() ) {
00132 KCal::Person person( name, email );
00133 KURL mailto;
00134 mailto.setProtocol( "mailto" );
00135 mailto.setPath( person.fullName() );
00136 tmpString += eventViewerAddLink( mailto.url(), QString::null );
00137 }
00138 tmpString += "</li>\n";
00139
00140 return tmpString;
00141 }
00142
00143 static QString eventViewerFormatAttendees( Incidence *event )
00144 {
00145 QString tmpStr;
00146 Attendee::List attendees = event->attendees();
00147 if ( attendees.count() ) {
00148
00149
00150 tmpStr += eventViewerAddTag( "i", i18n("Organizer") );
00151 tmpStr += "<ul>";
00152 tmpStr += linkPerson( event->organizer().email(),
00153 event->organizer().name(), QString::null );
00154 tmpStr += "</ul>";
00155
00156
00157 tmpStr += eventViewerAddTag( "i", i18n("Attendees") );
00158 tmpStr += "<ul>";
00159 Attendee::List::ConstIterator it;
00160 for( it = attendees.begin(); it != attendees.end(); ++it ) {
00161 Attendee *a = *it;
00162 tmpStr += linkPerson( a->email(), a->name(), a->uid() );
00163 }
00164 tmpStr += "</ul>";
00165 }
00166 return tmpStr;
00167 }
00168
00169 static QString eventViewerFormatAttachments( Incidence *i )
00170 {
00171 QString tmpStr;
00172 Attachment::List as = i->attachments();
00173 if ( as.count() > 0 ) {
00174 Attachment::List::ConstIterator it;
00175 for( it = as.begin(); it != as.end(); ++it ) {
00176 if ( (*it)->isUri() ) {
00177 QString name;
00178 if ( (*it)->uri().startsWith( "kmail:" ) )
00179 name = i18n( "Show mail" );
00180 else
00181 name = (*it)->uri();
00182 tmpStr += eventViewerAddLink( (*it)->uri(), name );
00183 tmpStr += "<br>";
00184 }
00185 }
00186 }
00187 return tmpStr;
00188 }
00189
00190
00191
00192
00193
00194 static QString eventViewerFormatBirthday( Event *event )
00195 {
00196 if ( !event) return QString::null;
00197 if ( event->customProperty("KABC","BIRTHDAY") != "YES" ) return QString::null;
00198
00199 QString uid = event->customProperty("KABC","UID-1");
00200 QString name = event->customProperty("KABC","NAME-1");
00201 QString email= event->customProperty("KABC","EMAIL-1");
00202
00203 QString tmpString = "<ul>";
00204 tmpString += linkPerson( email, name, uid );
00205
00206 if ( event->customProperty( "KABC", "ANNIVERSARY") == "YES" ) {
00207 uid = event->customProperty("KABC","UID-2");
00208 name = event->customProperty("KABC","NAME-2");
00209 email= event->customProperty("KABC","EMAIL-2");
00210 tmpString += linkPerson( email, name, uid );
00211 }
00212
00213 tmpString += "</ul>";
00214 return tmpString;
00215 }
00216
00217 static QString eventViewerFormatHeader( Incidence *incidence )
00218 {
00219 QString tmpStr = "<table><tr>";
00220
00221
00222 {
00223 tmpStr += "<td>";
00224
00225 if ( incidence->type() == "Event" ) {
00226 tmpStr += "<img src=\"" +
00227 KGlobal::iconLoader()->iconPath( "appointment", KIcon::Small ) +
00228 "\">";
00229 }
00230 if ( incidence->type() == "Todo" ) {
00231 tmpStr += "<img src=\"" +
00232 KGlobal::iconLoader()->iconPath( "todo", KIcon::Small ) +
00233 "\">";
00234 }
00235 if ( incidence->type() == "Journal" ) {
00236 tmpStr += "<img src=\"" +
00237 KGlobal::iconLoader()->iconPath( "journal", KIcon::Small ) +
00238 "\">";
00239 }
00240 if ( incidence->isAlarmEnabled() ) {
00241 tmpStr += "<img src=\"" +
00242 KGlobal::iconLoader()->iconPath( "bell", KIcon::Small ) +
00243 "\">";
00244 }
00245 if ( incidence->doesRecur() ) {
00246 tmpStr += "<img src=\"" +
00247 KGlobal::iconLoader()->iconPath( "recur", KIcon::Small ) +
00248 "\">";
00249 }
00250 if ( incidence->isReadOnly() ) {
00251 tmpStr += "<img src=\"" +
00252 KGlobal::iconLoader()->iconPath( "readonlyevent", KIcon::Small ) +
00253 "\">";
00254 }
00255
00256 tmpStr += "</td>";
00257 }
00258
00259 tmpStr += "<td>"
00260 + eventViewerAddTag( "u",
00261 eventViewerAddTag( "b", incidence->summary() ) )
00262 + "</td>";
00263 tmpStr += "</tr></table><br>";
00264
00265 return tmpStr;
00266 }
00267
00268 static QString eventViewerFormatEvent( Event *event )
00269 {
00270 if ( !event ) return QString::null;
00271 QString tmpStr = eventViewerFormatHeader( event );
00272
00273 tmpStr += "<table>";
00274
00275 tmpStr += "<tr>";
00276 if ( event->doesFloat() ) {
00277 if ( event->isMultiDay() ) {
00278 tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
00279 tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
00280 .arg( event->dtStartDateStr() )
00281 .arg( event->dtEndDateStr() ) + "</td>";
00282 } else {
00283 tmpStr += "<td align=\"right\"><b>" + i18n( "Date" ) + "</b></td>";
00284 tmpStr += "<td>" + i18n("date as string","%1").arg( event->dtStartDateStr() ) + "</td>";
00285 }
00286 } else {
00287 if ( event->isMultiDay() ) {
00288 tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
00289 tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
00290 .arg( event->dtStartStr() )
00291 .arg( event->dtEndStr() ) + "</td>";
00292 } else {
00293 tmpStr += "<td align=\"right\"><b>" + i18n( "Time" ) + "</b></td>";
00294 if ( event->hasEndDate() && event->dtStart() != event->dtEnd()) {
00295 tmpStr += "<td>" + i18n("<beginTime> - <endTime>","%1 - %2")
00296 .arg( event->dtStartTimeStr() )
00297 .arg( event->dtEndTimeStr() ) + "</td>";
00298 } else {
00299 tmpStr += "<td>" + event->dtStartTimeStr() + "</td>";
00300 }
00301 tmpStr += "</tr><tr>";
00302 tmpStr += "<td align=\"right\"><b>" + i18n( "Date" ) + "</b></td>";
00303 tmpStr += "<td>" + i18n("date as string","%1")
00304 .arg( event->dtStartDateStr() ) + "</td>";
00305 }
00306 }
00307 tmpStr += "</tr>";
00308
00309 if ( event->customProperty("KABC","BIRTHDAY")== "YES" ) {
00310 tmpStr += "<tr>";
00311 tmpStr += "<td align=\"right\"><b>" + i18n( "Birthday" ) + "</b></td>";
00312 tmpStr += "<td>" + eventViewerFormatBirthday( event ) + "</td>";
00313 tmpStr += "</tr>";
00314 tmpStr += "</table>";
00315 return tmpStr;
00316 }
00317
00318 if ( !event->description().isEmpty() ) {
00319 tmpStr += "<tr>";
00320 tmpStr += "<td align=\"right\"><b>" + i18n( "Description" ) + "</b></td>";
00321 tmpStr += "<td>" + eventViewerAddTag( "p", event->description() ) + "</td>";
00322 tmpStr += "</tr>";
00323 }
00324
00325 if ( !event->location().isEmpty() ) {
00326 tmpStr += "<tr>";
00327 tmpStr += "<td align=\"right\"><b>" + i18n( "Location" ) + "</b></td>";
00328 tmpStr += "<td>" + event->location() + "</td>";
00329 tmpStr += "</tr>";
00330 }
00331
00332 if ( event->categories().count() > 0 ) {
00333 tmpStr += "<tr>";
00334 tmpStr += "<td align=\"right\"><b>" + i18n( "1 Category", "%n Categories", event->categories().count() )+ "</b></td>";
00335 tmpStr += "<td>" + event->categoriesStr() + "</td>";
00336 tmpStr += "</tr>";
00337 }
00338
00339 if ( event->doesRecur() ) {
00340 QDateTime dt =
00341 event->recurrence()->getNextDateTime( QDateTime::currentDateTime() );
00342 tmpStr += "<tr>";
00343 tmpStr += "<td align=\"right\"><b>" + i18n( "Next on" ) + "</b></td>";
00344 if ( !event->doesFloat() ) {
00345 tmpStr += "<td>" +
00346 KGlobal::locale()->formatDateTime( dt, true ) + "</td>";
00347 } else {
00348 tmpStr += "<td>" +
00349 KGlobal::locale()->formatDate( dt.date(), true ) + "</td>";
00350 }
00351 tmpStr += "</tr>";
00352 }
00353
00354 int attendeeCount = event->attendees().count();
00355 if ( attendeeCount > 0 ) {
00356 tmpStr += "<tr><td colspan=\"2\">";
00357 tmpStr += eventViewerFormatAttendees( event );
00358 tmpStr += "</td></tr>";
00359 }
00360
00361 int attachmentCount = event->attachments().count();
00362 if ( attachmentCount > 0 ) {
00363 tmpStr += "<tr>";
00364 tmpStr += "<td align=\"right\"><b>" + i18n( "1 attachment", "%n attachments", attachmentCount )+ "</b></td>";
00365 tmpStr += "<td>" + eventViewerFormatAttachments( event ) + "</td>";
00366 tmpStr += "</tr>";
00367 }
00368
00369 tmpStr += "</table>";
00370 tmpStr += "<em>" + i18n( "Creation date: %1.").arg(
00371 KGlobal::locale()->formatDateTime( event->created() , true ) ) + "</em>";
00372 return tmpStr;
00373 }
00374
00375 static QString eventViewerFormatTodo( Todo *todo )
00376 {
00377 if ( !todo ) return QString::null;
00378 QString tmpStr = eventViewerFormatHeader( todo );
00379
00380 tmpStr += "<table>";
00381
00382 if ( todo->hasDueDate() ) {
00383 tmpStr += "<tr>";
00384 tmpStr += "<td align=\"right\"><b>" + i18n( "Due on" ) + "</b></td>";
00385 if ( !todo->doesFloat() ) {
00386 tmpStr += "<td>" +
00387 KGlobal::locale()->formatDateTime( todo->dtDue(), true ) +
00388 "</td>";
00389 } else {
00390 tmpStr += "<td>" +
00391 KGlobal::locale()->formatDate( todo->dtDue().date(), true ) +
00392 "</td>";
00393 }
00394 tmpStr += "</tr>";
00395 }
00396
00397 if ( !todo->description().isEmpty() ) {
00398 tmpStr += "<tr>";
00399 tmpStr += "<td align=\"right\"><b>" + i18n( "Description" ) + "</b></td>";
00400 tmpStr += "<td>" + todo->description() + "</td>";
00401 tmpStr += "</tr>";
00402 }
00403
00404 if ( !todo->location().isEmpty() ) {
00405 tmpStr += "<tr>";
00406 tmpStr += "<td align=\"right\"><b>" + i18n( "Location" ) + "</b></td>";
00407 tmpStr += "<td>" + todo->location() + "</td>";
00408 tmpStr += "</tr>";
00409 }
00410
00411 if ( todo->categories().count() > 0 ) {
00412 tmpStr += "<tr>";
00413 tmpStr += "<td align=\"right\"><b>" + i18n( "1 Category", "%n Categories", todo->categories().count() )+ "</b></td>";
00414 tmpStr += "<td>" + todo->categoriesStr() + "</td>";
00415 tmpStr += "</tr>";
00416 }
00417
00418 tmpStr += "<tr>";
00419 tmpStr += "<td align=\"right\"><b>" + i18n( "Priority" ) + "</b></td>";
00420 if ( todo->priority() > 0 ) {
00421 tmpStr += "<td>" + QString::number( todo->priority() ) + "</td>";
00422 } else {
00423 tmpStr += "<td>" + i18n( "Unspecified" ) + "</td>";
00424 }
00425 tmpStr += "</tr>";
00426
00427 tmpStr += "<tr>";
00428 tmpStr += "<td align=\"right\"><b>" + i18n( "Completed" ) + "</b></td>";
00429 tmpStr += "<td>" + i18n( "%1 %" ).arg( todo->percentComplete() ) + "</td>";
00430 tmpStr += "</tr>";
00431
00432 if ( todo->doesRecur() ) {
00433 QDateTime dt =
00434 todo->recurrence()->getNextDateTime( QDateTime::currentDateTime() );
00435 tmpStr += "<tr>";
00436 tmpStr += "<td align=\"right\"><b>" + i18n( "Next on" ) + "</b></td>";
00437 if ( !todo->doesFloat() ) {
00438 tmpStr += "<td>" +
00439 KGlobal::locale()->formatDateTime( dt, true ) + "</td>";
00440 } else {
00441 tmpStr += "<td>" +
00442 KGlobal::locale()->formatDate( dt.date(), true ) + "</td>";
00443 }
00444 tmpStr += "</tr>";
00445 }
00446
00447 int attendeeCount = todo->attendees().count();
00448 if ( attendeeCount > 0 ) {
00449 tmpStr += "<tr><td colspan=\"2\">";
00450 tmpStr += eventViewerFormatAttendees( todo );
00451 tmpStr += "</td></tr>";
00452 }
00453
00454 int attachmentCount = todo->attachments().count();
00455 if ( attachmentCount > 0 ) {
00456 tmpStr += "<tr>";
00457 tmpStr += "<td align=\"right\"><b>" + i18n( "1 attachment", "%n attachments", attachmentCount )+ "</b></td>";
00458 tmpStr += "<td>" + eventViewerFormatAttachments( todo ) + "</td>";
00459 tmpStr += "</tr>";
00460 }
00461
00462 tmpStr += "</table>";
00463 tmpStr += "<em>" + i18n( "Creation date: %1.").arg(
00464 KGlobal::locale()->formatDateTime( todo->created(), true ) ) + "</em>";
00465 return tmpStr;
00466 }
00467
00468 static QString eventViewerFormatJournal( Journal *journal )
00469 {
00470 if ( !journal ) return QString::null;
00471
00472 QString tmpStr;
00473 if ( !journal->summary().isEmpty() ) {
00474 tmpStr += eventViewerAddTag( "u",
00475 eventViewerAddTag( "b", journal->summary() ) );
00476 }
00477 tmpStr += eventViewerAddTag( "b", i18n("Journal for %1").arg( journal->dtStartDateStr( false ) ) );
00478 if ( !journal->description().isEmpty() )
00479 tmpStr += eventViewerAddTag( "p", journal->description() );
00480 return tmpStr;
00481 }
00482
00483 static QString eventViewerFormatFreeBusy( FreeBusy *fb )
00484 {
00485 if ( !fb ) return QString::null;
00486
00487 QString tmpStr =
00488 eventViewerAddTag( "u",
00489 eventViewerAddTag( "b", i18n("Free/Busy information for %1")
00490 .arg( fb->organizer().fullName() ) ) );
00491 tmpStr += eventViewerAddTag( "i", i18n("Busy times in date range %1 - %2:")
00492 .arg( KGlobal::locale()->formatDate( fb->dtStart().date(), true ) )
00493 .arg( KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) ) );
00494
00495 QValueList<Period> periods = fb->busyPeriods();
00496
00497 QString text = eventViewerAddTag( "em", eventViewerAddTag( "b", i18n("Busy:") ) );
00498 QValueList<Period>::iterator it;
00499 for ( it = periods.begin(); it != periods.end(); ++it ) {
00500 Period per = *it;
00501 if ( per.hasDuration() ) {
00502 int dur = per.duration().asSeconds();
00503 QString cont;
00504 if ( dur >= 3600 ) {
00505 cont += i18n("1 hour ", "%n hours ", dur / 3600 );
00506 dur %= 3600;
00507 }
00508 if ( dur >= 60 ) {
00509 cont += i18n("1 minute ", "%n minutes ", dur / 60);
00510 dur %= 60;
00511 }
00512 if ( dur > 0 ) {
00513 cont += i18n("1 second", "%n seconds", dur);
00514 }
00515 text += i18n("startDate for duration", "%1 for %2")
00516 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00517 .arg( cont );
00518 text += "<br>";
00519 } else {
00520 if ( per.start().date() == per.end().date() ) {
00521 text += i18n("date, fromTime - toTime ", "%1, %2 - %3")
00522 .arg( KGlobal::locale()->formatDate( per.start().date() ) )
00523 .arg( KGlobal::locale()->formatTime( per.start().time() ) )
00524 .arg( KGlobal::locale()->formatTime( per.end().time() ) );
00525 } else {
00526 text += i18n("fromDateTime - toDateTime", "%1 - %2")
00527 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00528 .arg( KGlobal::locale()->formatDateTime( per.end(), false ) );
00529 }
00530 text += "<br>";
00531 }
00532 }
00533 tmpStr += eventViewerAddTag( "p", text );
00534 return tmpStr;
00535 }
00536
00537 class IncidenceFormatter::EventViewerVisitor : public IncidenceBase::Visitor
00538 {
00539 public:
00540 EventViewerVisitor() { mResult = ""; }
00541 bool act( IncidenceBase *incidence ) { return incidence->accept( *this ); }
00542 QString result() const { return mResult; }
00543 protected:
00544 bool visit( Event *event )
00545 {
00546 mResult = eventViewerFormatEvent( event );
00547 return !mResult.isEmpty();
00548 }
00549 bool visit( Todo *todo )
00550 {
00551 mResult = eventViewerFormatTodo( todo );
00552 return !mResult.isEmpty();
00553 }
00554 bool visit( Journal *journal )
00555 {
00556 mResult = eventViewerFormatJournal( journal );
00557 return !mResult.isEmpty();
00558 }
00559 bool visit( FreeBusy *fb )
00560 {
00561 mResult = eventViewerFormatFreeBusy( fb );
00562 return !mResult.isEmpty();
00563 }
00564
00565 protected:
00566 QString mResult;
00567 };
00568
00569 QString IncidenceFormatter::extensiveDisplayString( IncidenceBase *incidence )
00570 {
00571 if ( !incidence ) return QString::null;
00572 EventViewerVisitor v;
00573 if ( v.act( incidence ) ) {
00574 return v.result();
00575 } else
00576 return QString::null;
00577 }
00578
00579
00580
00581
00582
00583
00584
00585
00586 static QString string2HTML( const QString& str )
00587 {
00588 return QStyleSheet::convertFromPlainText(str);
00589 }
00590
00591 static QString invitationRow( const QString &cell1, const QString &cell2 )
00592 {
00593 return "<tr><td>" + cell1 + "</td><td>" + cell2 + "</td></tr>\n";
00594 }
00595
00596 static QString invitationDetailsEvent( Event* event )
00597 {
00598
00599 if ( !event )
00600 return QString::null;
00601
00602 QString html;
00603 QString tmp;
00604
00605 QString sSummary = i18n( "Summary unspecified" );
00606 if ( ! event->summary().isEmpty() ) {
00607 sSummary = string2HTML( event->summary() );
00608 }
00609
00610 QString sLocation = i18n( "Location unspecified" );
00611 if ( ! event->location().isEmpty() ) {
00612 sLocation = string2HTML( event->location() );
00613 }
00614
00615 QString dir = ( QApplication::reverseLayout() ? "rtl" : "ltr" );
00616 html = QString("<div dir=\"%1\">\n").arg(dir);
00617
00618 html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
00619
00620
00621 html += invitationRow( i18n( "What:" ), sSummary );
00622 html += invitationRow( i18n( "Where:" ), sLocation );
00623
00624
00625 if ( ! event->doesFloat() ) {
00626 tmp = i18n("%1: Start Date, %2: Start Time", "%1 %2")
00627 .arg( event->dtStartDateStr(), event->dtStartTimeStr() );
00628 } else {
00629 tmp = i18n("%1: Start Date", "%1 (time unspecified)")
00630 .arg( event->dtStartDateStr() );
00631 }
00632 html += invitationRow( i18n( "Start Time:" ), tmp );
00633
00634
00635 if ( event->hasEndDate() ) {
00636 if ( ! event->doesFloat() ) {
00637 tmp = i18n("%1: End Date, %2: End Time", "%1 %2")
00638 .arg( event->dtEndDateStr(), event->dtEndTimeStr() );
00639 } else {
00640 tmp = i18n("%1: End Date", "%1 (time unspecified)")
00641 .arg( event->dtEndDateStr() );
00642 }
00643 } else {
00644 tmp = i18n( "Unspecified" );
00645 }
00646 html += invitationRow( i18n( "End Time:" ), tmp );
00647
00648
00649 if ( !event->doesFloat() && event->hasEndDate() ) {
00650 tmp = QString::null;
00651 QTime sDuration(0,0,0), t;
00652 int secs = event->dtStart().secsTo( event->dtEnd() );
00653 t = sDuration.addSecs( secs );
00654 if ( t.hour() > 0 ) {
00655 tmp += i18n( "1 hour ", "%n hours ", t.hour() );
00656 }
00657 if ( t.minute() > 0 ) {
00658 tmp += i18n( "1 minute ", "%n minutes ", t.minute() );
00659 }
00660
00661 html += invitationRow( i18n( "Duration:" ), tmp );
00662 }
00663
00664 html += "</table>\n";
00665 html += "</div>\n";
00666
00667 return html;
00668 }
00669
00670 static QString invitationDetailsTodo( Todo *todo )
00671 {
00672
00673 if ( !todo )
00674 return QString::null;
00675
00676 QString sSummary = i18n( "Summary unspecified" );
00677 QString sDescr = i18n( "Description unspecified" );
00678 if ( ! todo->summary().isEmpty() ) {
00679 sSummary = todo->summary();
00680 }
00681 if ( ! todo->description().isEmpty() ) {
00682 sDescr = todo->description();
00683 }
00684 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00685 html += invitationRow( i18n( "Summary:" ), sSummary );
00686 html += invitationRow( i18n( "Description:" ), sDescr );
00687 html += "</table>\n";
00688
00689 return html;
00690 }
00691
00692 static QString invitationDetailsJournal( Journal *journal )
00693 {
00694 if ( !journal )
00695 return QString::null;
00696
00697 QString sSummary = i18n( "Summary unspecified" );
00698 QString sDescr = i18n( "Description unspecified" );
00699 if ( ! journal->summary().isEmpty() ) {
00700 sSummary = journal->summary();
00701 }
00702 if ( ! journal->description().isEmpty() ) {
00703 sDescr = journal->description();
00704 }
00705 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00706 html += invitationRow( i18n( "Summary:" ), sSummary );
00707 html += invitationRow( i18n( "Date:" ), journal->dtStartDateStr( false ) );
00708 html += invitationRow( i18n( "Description:" ), sDescr );
00709 html += "</table>\n";
00710
00711 return html;
00712 }
00713
00714 static QString invitationDetailsFreeBusy( FreeBusy *fb )
00715 {
00716 if ( !fb )
00717 return QString::null;
00718 QString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
00719
00720 html += invitationRow( i18n("Person:"), fb->organizer().fullName() );
00721 html += invitationRow( i18n("Start date:"), fb->dtStartDateStr() );
00722 html += invitationRow( i18n("End date:"),
00723 KGlobal::locale()->formatDate( fb->dtEnd().date(), true ) );
00724 html += "<tr><td colspan=2><hr></td></tr>\n";
00725 html += "<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n";
00726
00727 QValueList<Period> periods = fb->busyPeriods();
00728
00729 QValueList<Period>::iterator it;
00730 for ( it = periods.begin(); it != periods.end(); ++it ) {
00731 Period per = *it;
00732 if ( per.hasDuration() ) {
00733 int dur = per.duration().asSeconds();
00734 QString cont;
00735 if ( dur >= 3600 ) {
00736 cont += i18n("1 hour ", "%n hours ", dur / 3600);
00737 dur %= 3600;
00738 }
00739 if ( dur >= 60 ) {
00740 cont += i18n("1 minute", "%n minutes ", dur / 60);
00741 dur %= 60;
00742 }
00743 if ( dur > 0 ) {
00744 cont += i18n("1 second", "%n seconds", dur);
00745 }
00746 html += invitationRow( QString::null, i18n("startDate for duration", "%1 for %2")
00747 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00748 .arg(cont) );
00749 } else {
00750 QString cont;
00751 if ( per.start().date() == per.end().date() ) {
00752 cont = i18n("date, fromTime - toTime ", "%1, %2 - %3")
00753 .arg( KGlobal::locale()->formatDate( per.start().date() ) )
00754 .arg( KGlobal::locale()->formatTime( per.start().time() ) )
00755 .arg( KGlobal::locale()->formatTime( per.end().time() ) );
00756 } else {
00757 cont = i18n("fromDateTime - toDateTime", "%1 - %2")
00758 .arg( KGlobal::locale()->formatDateTime( per.start(), false ) )
00759 .arg( KGlobal::locale()->formatDateTime( per.end(), false ) );
00760 }
00761
00762 html += invitationRow( QString::null, cont );
00763 }
00764 }
00765
00766 html += "</table>\n";
00767 return html;
00768 }
00769
00770 static QString invitationHeaderEvent( Event *event, ScheduleMessage *msg )
00771 {
00772 if ( !msg || !event )
00773 return QString::null;
00774 switch ( msg->method() ) {
00775 case Scheduler::Publish:
00776 return i18n("This event has been published");
00777 case Scheduler::Request:
00778 return i18n( "You have been invited to this meeting" );
00779 case Scheduler::Refresh:
00780 return i18n( "This invitation was refreshed" );
00781 case Scheduler::Cancel:
00782 return i18n( "This meeting has been canceled" );
00783 case Scheduler::Add:
00784 return i18n( "Addition to the meeting invitation" );
00785 case Scheduler::Reply: {
00786 Attendee::List attendees = event->attendees();
00787 if( attendees.count() == 0 ) {
00788 kdDebug(5850) << "No attendees in the iCal reply!\n";
00789 return QString::null;
00790 }
00791 if( attendees.count() != 1 )
00792 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
00793 << "but is " << attendees.count() << endl;
00794 Attendee* attendee = *attendees.begin();
00795
00796 switch( attendee->status() ) {
00797 case Attendee::NeedsAction:
00798 return i18n( "Sender indicates this invitation still needs some action" );
00799 case Attendee::Accepted:
00800 return i18n( "Sender accepts this meeting invitation" );
00801 case Attendee::Tentative:
00802 return i18n( "Sender tentatively accepts this meeting invitation" );
00803 case Attendee::Declined:
00804 return i18n( "Sender declines this meeting invitation" );
00805 case Attendee::Delegated:
00806 return i18n( "Sender has delegated this meeting invitation" );
00807 case Attendee::Completed:
00808 return i18n( "This meeting invitation is now completed" );
00809 case Attendee::InProcess:
00810 return i18n( "Sender is still processing the invitation" );
00811 default:
00812 return i18n( "Unknown response to this meeting invitation" );
00813 }
00814 break; }
00815 case Scheduler::Counter:
00816 return i18n( "Sender makes this counter proposal" );
00817 case Scheduler::Declinecounter:
00818 return i18n( "Sender declines the counter proposal" );
00819 case Scheduler::NoMethod:
00820 return i18n("Error: iMIP message with unknown method: '%1'")
00821 .arg( msg->method() );
00822 }
00823 return QString::null;
00824 }
00825
00826 static QString invitationHeaderTodo( Todo *todo, ScheduleMessage *msg )
00827 {
00828 if ( !msg || !todo )
00829 return QString::null;
00830 switch ( msg->method() ) {
00831 case Scheduler::Publish:
00832 return i18n("This task has been published");
00833 case Scheduler::Request:
00834 return i18n( "You have been assigned this task" );
00835 case Scheduler::Refresh:
00836 return i18n( "This task was refreshed" );
00837 case Scheduler::Cancel:
00838 return i18n( "This task was canceled" );
00839 case Scheduler::Add:
00840 return i18n( "Addition to the task" );
00841 case Scheduler::Reply: {
00842 Attendee::List attendees = todo->attendees();
00843 if( attendees.count() == 0 ) {
00844 kdDebug(5850) << "No attendees in the iCal reply!\n";
00845 return QString::null;
00846 }
00847 if( attendees.count() != 1 )
00848 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
00849 << "but is " << attendees.count() << endl;
00850 Attendee* attendee = *attendees.begin();
00851
00852 switch( attendee->status() ) {
00853 case Attendee::NeedsAction:
00854 return i18n( "Sender indicates this task assignment still needs some action" );
00855 case Attendee::Accepted:
00856 return i18n( "Sender accepts this task" );
00857 case Attendee::Tentative:
00858 return i18n( "Sender tentatively accepts this task" );
00859 case Attendee::Declined:
00860 return i18n( "Sender declines this task" );
00861 case Attendee::Delegated:
00862 return i18n( "Sender has delegated this request for the task " );
00863 case Attendee::Completed:
00864 return i18n( "The request for this task is now completed" );
00865 case Attendee::InProcess:
00866 return i18n( "Sender is still processing the invitation" );
00867 default:
00868 return i18n( "Unknown response to this task" );
00869 }
00870 break; }
00871 case Scheduler::Counter:
00872 return i18n( "Sender makes this counter proposal" );
00873 case Scheduler::Declinecounter:
00874 return i18n( "Sender declines the counter proposal" );
00875 case Scheduler::NoMethod:
00876 return i18n("Error: iMIP message with unknown method: '%1'")
00877 .arg( msg->method() );
00878 }
00879 return QString::null;
00880 }
00881
00882 static QString invitationHeaderJournal( Journal *journal, ScheduleMessage *msg )
00883 {
00884
00885 if ( !msg || !journal )
00886 return QString::null;
00887 switch ( msg->method() ) {
00888 case Scheduler::Publish:
00889 return i18n("This journal has been published");
00890 case Scheduler::Request:
00891 return i18n( "You have been assigned this journal" );
00892 case Scheduler::Refresh:
00893 return i18n( "This journal was refreshed" );
00894 case Scheduler::Cancel:
00895 return i18n( "This journal was canceled" );
00896 case Scheduler::Add:
00897 return i18n( "Addition to the journal" );
00898 case Scheduler::Reply: {
00899 Attendee::List attendees = journal->attendees();
00900 if( attendees.count() == 0 ) {
00901 kdDebug(5850) << "No attendees in the iCal reply!\n";
00902 return QString::null;
00903 }
00904 if( attendees.count() != 1 )
00905 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
00906 << "but is " << attendees.count() << endl;
00907 Attendee* attendee = *attendees.begin();
00908
00909 switch( attendee->status() ) {
00910 case Attendee::NeedsAction:
00911 return i18n( "Sender indicates this journal assignment still needs some action" );
00912 case Attendee::Accepted:
00913 return i18n( "Sender accepts this journal" );
00914 case Attendee::Tentative:
00915 return i18n( "Sender tentatively accepts this journal" );
00916 case Attendee::Declined:
00917 return i18n( "Sender declines this journal" );
00918 case Attendee::Delegated:
00919 return i18n( "Sender has delegated this request for the journal" );
00920 case Attendee::Completed:
00921 return i18n( "The request for this journal is now completed" );
00922 case Attendee::InProcess:
00923 return i18n( "Sender is still processing the invitation" );
00924 default:
00925 return i18n( "Unknown response to this journal" );
00926 }
00927 break; }
00928 case Scheduler::Counter:
00929 return i18n( "Sender makes this counter proposal" );
00930 case Scheduler::Declinecounter:
00931 return i18n( "Sender declines the counter proposal" );
00932 case Scheduler::NoMethod:
00933 return i18n("Error: iMIP message with unknown method: '%1'")
00934 .arg( msg->method() );
00935 }
00936 return QString::null;
00937 }
00938
00939 static QString invitationHeaderFreeBusy( FreeBusy *fb, ScheduleMessage *msg )
00940 {
00941 if ( !msg || !fb )
00942 return QString::null;
00943 switch ( msg->method() ) {
00944 case Scheduler::Publish:
00945 return i18n("This free/busy list has been published");
00946 case Scheduler::Request:
00947 return i18n( "The free/busy list has been requested" );
00948 case Scheduler::Refresh:
00949 return i18n( "This free/busy list was refreshed" );
00950 case Scheduler::Cancel:
00951 return i18n( "This free/busy list was canceled" );
00952 case Scheduler::Add:
00953 return i18n( "Addition to the free/busy list" );
00954 case Scheduler::NoMethod:
00955 default:
00956 return i18n("Error: Free/Busy iMIP message with unknown method: '%1'")
00957 .arg( msg->method() );
00958 }
00959 }
00960
00961 class IncidenceFormatter::ScheduleMessageVisitor : public IncidenceBase::Visitor
00962 {
00963 public:
00964 ScheduleMessageVisitor() : mMessage(0) { mResult = ""; }
00965 bool act( IncidenceBase *incidence, ScheduleMessage *msg ) { mMessage = msg; return incidence->accept( *this ); }
00966 QString result() const { return mResult; }
00967
00968 protected:
00969 QString mResult;
00970 ScheduleMessage *mMessage;
00971 };
00972
00973 class IncidenceFormatter::InvitationHeaderVisitor :
00974 public IncidenceFormatter::ScheduleMessageVisitor
00975 {
00976 protected:
00977 bool visit( Event *event )
00978 {
00979 mResult = invitationHeaderEvent( event, mMessage );
00980 return !mResult.isEmpty();
00981 }
00982 bool visit( Todo *todo )
00983 {
00984 mResult = invitationHeaderTodo( todo, mMessage );
00985 return !mResult.isEmpty();
00986 }
00987 bool visit( Journal *journal )
00988 {
00989 mResult = invitationHeaderJournal( journal, mMessage );
00990 return !mResult.isEmpty();
00991 }
00992 bool visit( FreeBusy *fb )
00993 {
00994 mResult = invitationHeaderFreeBusy( fb, mMessage );
00995 return !mResult.isEmpty();
00996 }
00997 };
00998
00999 class IncidenceFormatter::InvitationBodyVisitor :
01000 public IncidenceFormatter::ScheduleMessageVisitor
01001 {
01002 protected:
01003 bool visit( Event *event )
01004 {
01005 mResult = invitationDetailsEvent( event );
01006 return !mResult.isEmpty();
01007 }
01008 bool visit( Todo *todo )
01009 {
01010 mResult = invitationDetailsTodo( todo );
01011 return !mResult.isEmpty();
01012 }
01013 bool visit( Journal *journal )
01014 {
01015 mResult = invitationDetailsJournal( journal );
01016 return !mResult.isEmpty();
01017 }
01018 bool visit( FreeBusy *fb )
01019 {
01020 mResult = invitationDetailsFreeBusy( fb );
01021 return !mResult.isEmpty();
01022 }
01023 };
01024
01025
01026 QString InvitationFormatterHelper::makeLink( const QString &id, const QString &text )
01027 {
01028 QString res( "<a href=\"%1\"><b>%2</b></a>" );
01029 return res.arg( generateLinkURL( id ) ).arg( text );
01030 return res;
01031 }
01032
01033
01034 QString IncidenceFormatter::formatICalInvitation( QString invitation, Calendar *mCalendar,
01035 InvitationFormatterHelper *helper )
01036 {
01037 if ( invitation.isEmpty() ) return QString::null;
01038
01039 ICalFormat format;
01040
01041 ScheduleMessage *msg = format.parseScheduleMessage( mCalendar, invitation );
01042
01043 if( !msg ) {
01044 kdDebug( 5850 ) << "Failed to parse the scheduling message" << endl;
01045 Q_ASSERT( format.exception() );
01046 kdDebug( 5850 ) << format.exception()->message() << endl;
01047 return QString::null;
01048 }
01049
01050 IncidenceBase *incBase = msg->event();
01051
01052
01053 QString html;
01054
01055 QString tableStyle = QString::fromLatin1(
01056 "style=\"border: solid 1px; margin: 0em;\"" );
01057 QString tableHead = QString::fromLatin1(
01058 "<div align=\"center\">"
01059 "<table width=\"80%\" cellpadding=\"1\" cellspacing=\"0\" %1>"
01060 "<tr><td>").arg(tableStyle);
01061
01062 html += tableHead;
01063 InvitationHeaderVisitor headerVisitor;
01064
01065 if ( !headerVisitor.act( incBase, msg ) )
01066 return QString::null;
01067 html += "<b>" + headerVisitor.result() + "</b>";
01068
01069 InvitationBodyVisitor bodyVisitor;
01070 if ( !bodyVisitor.act( incBase, msg ) )
01071 return QString::null;
01072 html += bodyVisitor.result();
01073
01074 html += "<br> <br> <br>";
01075 html += "<table border=\"0\" cellspacing=\"0\"><tr><td> </td><td>";
01076
01077 #if 0
01078 html += helper->makeLinkURL( "accept", i18n("[Enter this into my calendar]") );
01079 html += "</td><td> </td><td>";
01080 #endif
01081
01082
01083
01084 switch ( msg->method() ) {
01085 case Scheduler::Publish:
01086 case Scheduler::Request:
01087 case Scheduler::Refresh:
01088 case Scheduler::Add:
01089
01090 html += helper->makeLink( "accept", i18n( "[Accept]" ) );
01091 html += "</td><td> </td><td>";
01092 html += helper->makeLink( "accept_conditionally",
01093 i18n( "Accept conditionally", "[Accept cond.]" ) );
01094 html += "</td><td> </td><td>";
01095
01096 html += helper->makeLink( "decline", i18n( "[Decline]" ) );
01097 #if 0
01098
01099 html += "</b></a></td><td> </td><td>";
01100 html += helper->makeLink( "check_calendar", i18n("[Check my calendar...]" ) );
01101 #endif
01102 break;
01103
01104 case Scheduler::Cancel:
01105
01106 html += helper->makeLink( "cancel", i18n( "[Remove this from my calendar]" ) );
01107 break;
01108
01109 case Scheduler::Reply:
01110
01111 if ( incBase->type() == "Todo" ) {
01112 html += helper->makeLink( "reply", i18n( "[Enter this into my task list]" ) );
01113 } else {
01114 html += helper->makeLink( "reply", i18n( "[Enter this into my calendar]" ) );
01115 }
01116 break;
01117
01118 case Scheduler::Counter:
01119 case Scheduler::Declinecounter:
01120 case Scheduler::NoMethod:
01121 break;
01122 }
01123
01124 html += "</td></tr></table>";
01125
01126 Incidence* incidence = dynamic_cast<Incidence*>( incBase );
01127 if ( incidence ) {
01128 QString sDescr = incidence->description();
01129 if( ( msg->method() == Scheduler::Request || msg->method() == Scheduler::Cancel ) &&
01130 !sDescr.isEmpty() ) {
01131 html += "<br> <br> <br><u>" + i18n("Description:")
01132 + "</u><br><table border=\"0\"><tr><td> </td><td>";
01133 html += string2HTML(sDescr) + "</td></tr></table>";
01134 }
01135 }
01136
01137 html += "</td></tr></table><br></div>";
01138
01139 return html;
01140 }
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152 static QString stringProp( KTNEFMessage* tnefMsg, const Q_UINT32& key,
01153 const QString& fallback = QString::null)
01154 {
01155 return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16,
01156 fallback );
01157 }
01158
01159 static QString sNamedProp( KTNEFMessage* tnefMsg, const QString& name,
01160 const QString& fallback = QString::null )
01161 {
01162 return tnefMsg->findNamedProp( name, fallback );
01163 }
01164
01165 struct save_tz { char* old_tz; char* tz_env_str; };
01166
01167
01168 static struct save_tz set_tz( const char* _tc )
01169 {
01170 const char *tc = _tc?_tc:"UTC";
01171
01172 struct save_tz rv;
01173
01174 rv.old_tz = 0;
01175 rv.tz_env_str = 0;
01176
01177
01178
01179 char* tz_env = 0;
01180 if( getenv( "TZ" ) ) {
01181 tz_env = strdup( getenv( "TZ" ) );
01182 rv.old_tz = tz_env;
01183 }
01184 char* tmp_env = (char*)malloc( strlen( tc ) + 4 );
01185 strcpy( tmp_env, "TZ=" );
01186 strcpy( tmp_env+3, tc );
01187 putenv( tmp_env );
01188
01189 rv.tz_env_str = tmp_env;
01190
01191
01192
01193 tzset();
01194
01195
01196 return rv;
01197 }
01198
01199
01200 static void unset_tz( struct save_tz old_tz )
01201 {
01202 if( old_tz.old_tz ) {
01203 char* tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 );
01204 strcpy( tmp_env, "TZ=" );
01205 strcpy( tmp_env+3, old_tz.old_tz );
01206 putenv( tmp_env );
01207
01208 free( old_tz.old_tz );
01209 } else {
01210
01211 putenv( strdup("TZ") );
01212 }
01213 tzset();
01214
01215
01216 if( old_tz.tz_env_str ) free( old_tz.tz_env_str );
01217 }
01218
01219 static QDateTime utc2Local( const QDateTime& utcdt )
01220 {
01221 struct tm tmL;
01222
01223 save_tz tmp_tz = set_tz("UTC");
01224 time_t utc = utcdt.toTime_t();
01225 unset_tz( tmp_tz );
01226
01227 localtime_r( &utc, &tmL );
01228 return QDateTime( QDate( tmL.tm_year+1900, tmL.tm_mon+1, tmL.tm_mday ),
01229 QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
01230 }
01231
01232
01233 static QDateTime pureISOToLocalQDateTime( const QString& dtStr,
01234 bool bDateOnly = false )
01235 {
01236 QDate tmpDate;
01237 QTime tmpTime;
01238 int year, month, day, hour, minute, second;
01239
01240 if( bDateOnly ) {
01241 year = dtStr.left( 4 ).toInt();
01242 month = dtStr.mid( 4, 2 ).toInt();
01243 day = dtStr.mid( 6, 2 ).toInt();
01244 hour = 0;
01245 minute = 0;
01246 second = 0;
01247 } else {
01248 year = dtStr.left( 4 ).toInt();
01249 month = dtStr.mid( 4, 2 ).toInt();
01250 day = dtStr.mid( 6, 2 ).toInt();
01251 hour = dtStr.mid( 9, 2 ).toInt();
01252 minute = dtStr.mid( 11, 2 ).toInt();
01253 second = dtStr.mid( 13, 2 ).toInt();
01254 }
01255 tmpDate.setYMD( year, month, day );
01256 tmpTime.setHMS( hour, minute, second );
01257
01258 if( tmpDate.isValid() && tmpTime.isValid() ) {
01259 QDateTime dT = QDateTime( tmpDate, tmpTime );
01260
01261 if( !bDateOnly ) {
01262
01263 if (dtStr.at(dtStr.length()-1) == 'Z') {
01264
01265
01266 dT = utc2Local( dT );
01267 }
01268 }
01269 return dT;
01270 } else
01271 return QDateTime();
01272 }
01273
01274
01275
01276 QString IncidenceFormatter::msTNEFToVPart( const QByteArray& tnef )
01277 {
01278 bool bOk = false;
01279
01280 KTNEFParser parser;
01281 QBuffer buf( tnef );
01282 CalendarLocal cal ( QString::fromLatin1( "UTC" ) );
01283 KABC::Addressee addressee;
01284 KABC::VCardConverter cardConv;
01285 ICalFormat calFormat;
01286 Event* event = new Event();
01287
01288 if( parser.openDevice( &buf ) ) {
01289 KTNEFMessage* tnefMsg = parser.message();
01290
01291
01292
01293
01294 QString msgClass = tnefMsg->findProp( 0x001A, QString::null, true )
01295 .upper();
01296 if( !msgClass.isEmpty() ) {
01297
01298
01299 bool bCompatClassAppointment = false;
01300 bool bCompatMethodRequest = false;
01301 bool bCompatMethodCancled = false;
01302 bool bCompatMethodAccepted = false;
01303 bool bCompatMethodAcceptedCond = false;
01304 bool bCompatMethodDeclined = false;
01305 if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ) {
01306 bCompatClassAppointment = true;
01307 if( msgClass.endsWith( ".MTGREQ" ) )
01308 bCompatMethodRequest = true;
01309 if( msgClass.endsWith( ".MTGCNCL" ) )
01310 bCompatMethodCancled = true;
01311 if( msgClass.endsWith( ".MTGRESPP" ) )
01312 bCompatMethodAccepted = true;
01313 if( msgClass.endsWith( ".MTGRESPA" ) )
01314 bCompatMethodAcceptedCond = true;
01315 if( msgClass.endsWith( ".MTGRESPN" ) )
01316 bCompatMethodDeclined = true;
01317 }
01318 bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" );
01319
01320 if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) {
01321
01322 bool bIsReply = false;
01323 QString prodID = "-//Microsoft Corporation//Outlook ";
01324 prodID += tnefMsg->findNamedProp( "0x8554", "9.0" );
01325 prodID += "MIMEDIR/EN\n";
01326 prodID += "VERSION:2.0\n";
01327 calFormat.setApplication( "Outlook", prodID );
01328
01329 Scheduler::Method method;
01330 if( bCompatMethodRequest )
01331 method = Scheduler::Request;
01332 else if( bCompatMethodCancled )
01333 method = Scheduler::Cancel;
01334 else if( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
01335 bCompatMethodDeclined ) {
01336 method = Scheduler::Reply;
01337 bIsReply = true;
01338 } else {
01339
01340
01341
01342
01343
01344
01345
01346
01347 if( tnefMsg->findProp(0x0c17) == "1" )
01348 bIsReply = true;
01349 method = Scheduler::Request;
01350 }
01351
01353 ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown );
01354
01355 QString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) );
01356
01357 if( !sSenderSearchKeyEmail.isEmpty() ) {
01358 int colon = sSenderSearchKeyEmail.find( ':' );
01359
01360 if( sSenderSearchKeyEmail.find( ':' ) == -1 )
01361 sSenderSearchKeyEmail.remove( 0, colon+1 );
01362 }
01363
01364 QString s( tnefMsg->findProp( 0x0e04 ) );
01365 QStringList attendees = QStringList::split( ';', s );
01366 if( attendees.count() ) {
01367 for( QStringList::Iterator it = attendees.begin();
01368 it != attendees.end(); ++it ) {
01369
01370
01371 if( (*it).find('@') == -1 ) {
01372 s = (*it).stripWhiteSpace();
01373
01374 Attendee *attendee = new Attendee( s, s, true );
01375 if( bIsReply ) {
01376 if( bCompatMethodAccepted )
01377 attendee->setStatus( Attendee::Accepted );
01378 if( bCompatMethodDeclined )
01379 attendee->setStatus( Attendee::Declined );
01380 if( bCompatMethodAcceptedCond )
01381 attendee->setStatus(Attendee::Tentative);
01382 } else {
01383 attendee->setStatus( Attendee::NeedsAction );
01384 attendee->setRole( Attendee::ReqParticipant );
01385 }
01386 event->addAttendee(attendee);
01387 }
01388 }
01389 } else {
01390
01391
01392 s = sSenderSearchKeyEmail;
01393 if( !s.isEmpty() ) {
01394 Attendee *attendee = new Attendee( QString::null, QString::null,
01395 true );
01396 if( bIsReply ) {
01397 if( bCompatMethodAccepted )
01398 attendee->setStatus( Attendee::Accepted );
01399 if( bCompatMethodAcceptedCond )
01400 attendee->setStatus( Attendee::Declined );
01401 if( bCompatMethodDeclined )
01402 attendee->setStatus( Attendee::Tentative );
01403 } else {
01404 attendee->setStatus(Attendee::NeedsAction);
01405 attendee->setRole(Attendee::ReqParticipant);
01406 }
01407 event->addAttendee(attendee);
01408 }
01409 }
01410 s = tnefMsg->findProp( 0x0c1f );
01411 if( s.isEmpty() && !bIsReply )
01412 s = sSenderSearchKeyEmail;
01413
01414 if( !s.isEmpty() )
01415 event->setOrganizer( s );
01416
01417 s = tnefMsg->findProp( 0x8516 ).replace( QChar( '-' ), QString::null )
01418 .replace( QChar( ':' ), QString::null );
01419 event->setDtStart( QDateTime::fromString( s ) );
01420
01421 s = tnefMsg->findProp( 0x8517 ).replace( QChar( '-' ), QString::null )
01422 .replace( QChar( ':' ), QString::null );
01423 event->setDtEnd( QDateTime::fromString( s ) );
01424
01425 s = tnefMsg->findProp( 0x8208 );
01426 event->setLocation( s );
01427
01428
01429
01430
01431
01432
01433 s = tnefMsg->findProp( 0x0023 );
01434 event->setUid( s );
01435
01436
01437
01438
01439 s = tnefMsg->findProp( 0x8202 ).replace( QChar( '-' ), QString::null )
01440 .replace( QChar( ':' ), QString::null );
01441
01442
01443
01444 s = tnefMsg->findNamedProp( "Keywords" );
01445 event->setCategories( s );
01446
01447 s = tnefMsg->findProp( 0x1000 );
01448 event->setDescription( s );
01449
01450 s = tnefMsg->findProp( 0x0070 );
01451 event->setSummary( s );
01452
01453 s = tnefMsg->findProp( 0x0026 );
01454 event->setPriority( s.toInt() );
01455
01456
01457 if(!tnefMsg->findProp(0x8503).isEmpty()) {
01458 Alarm *alarm = new Alarm(event);
01459 QDateTime highNoonTime =
01460 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8502 )
01461 .replace( QChar( '-' ), "" )
01462 .replace( QChar( ':' ), "" ) );
01463 QDateTime wakeMeUpTime =
01464 pureISOToLocalQDateTime( tnefMsg->findProp( 0x8560, "" )
01465 .replace( QChar( '-' ), "" )
01466 .replace( QChar( ':' ), "" ) );
01467 alarm->setTime(wakeMeUpTime);
01468
01469 if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
01470 alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
01471 else
01472
01473 alarm->setStartOffset( Duration( 15*60 ) );
01474 alarm->setDisplayAlarm( i18n( "Reminder" ) );
01475
01476
01477
01478 event->addAlarm( alarm );
01479 }
01480 cal.addEvent( event );
01481 bOk = true;
01482
01483 } else if( bCompatClassNote || "IPM.CONTACT" == msgClass ) {
01484 addressee.setUid( stringProp( tnefMsg, attMSGID ) );
01485 addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
01486 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true );
01487 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false );
01488 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false );
01489 addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
01490 addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
01491 addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
01492 addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
01493 addressee.insertCustom( "KADDRESSBOOK", "X-Department", stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
01494 addressee.insertCustom( "KADDRESSBOOK", "X-Office", stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
01495 addressee.insertCustom( "KADDRESSBOOK", "X-Profession", stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
01496
01497 QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY )
01498 .replace( QChar( '-' ), QString::null )
01499 .replace( QChar( ':' ), QString::null );
01500 if( !s.isEmpty() )
01501 addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s );
01502
01503 addressee.setUrl( KURL( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) );
01504
01505
01506 addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
01507 addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
01508 addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
01509 addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
01510 addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
01511
01512 addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
01513 addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
01514 addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
01515
01516
01517
01518
01519
01520 KABC::Address adr;
01521 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
01522 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
01523 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
01524 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
01525 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
01526 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
01527 adr.setType(KABC::Address::Home);
01528 addressee.insertAddress(adr);
01529
01530 adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
01531 adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
01532 adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
01533 adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
01534 adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
01535 adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
01536 adr.setType( KABC::Address::Work );
01537 addressee.insertAddress( adr );
01538
01539 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
01540 adr.setStreet( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
01541 adr.setLocality( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
01542 adr.setRegion( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
01543 adr.setPostalCode( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
01544 adr.setCountry( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
01545 adr.setType( KABC::Address::Dom );
01546 addressee.insertAddress(adr);
01547
01548
01549
01550
01551
01552 QString nr;
01553 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
01554 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) );
01555 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
01556 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) );
01557 nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
01558 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) );
01559 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
01560 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) );
01561 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
01562 addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) );
01563
01564 s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY )
01565 .replace( QChar( '-' ), QString::null )
01566 .replace( QChar( ':' ), QString::null );
01567 if( !s.isEmpty() )
01568 addressee.setBirthday( QDateTime::fromString( s ) );
01569
01570 bOk = ( !addressee.isEmpty() );
01571 } else if( "IPM.NOTE" == msgClass ) {
01572
01573 }
01574 }
01575 }
01576
01577
01578 QString iCal = calFormat.toString( &cal );
01579 if( !iCal.isEmpty() )
01580
01581 return iCal;
01582
01583
01584 KABC::VCardConverter converter;
01585 return converter.createVCard( addressee );
01586 }
01587
01588
01589 QString IncidenceFormatter::formatTNEFInvitation( const QByteArray& tnef,
01590 Calendar *mCalendar, InvitationFormatterHelper *helper )
01591 {
01592 QString vPart = IncidenceFormatter::msTNEFToVPart( tnef );
01593 QString iCal = IncidenceFormatter::formatICalInvitation( vPart, mCalendar, helper );
01594 if( !iCal.isEmpty() )
01595 return iCal;
01596 return vPart;
01597 }
01598
01599
01600
01601
01602
01603
01604
01605
01606 class IncidenceFormatter::ToolTipVisitor : public IncidenceBase::Visitor
01607 {
01608 public:
01609 ToolTipVisitor() : mRichText( true ), mResult( "" ) {}
01610
01611 bool act( IncidenceBase *incidence, bool richText=true)
01612 {
01613 mRichText = richText;
01614 mResult = "";
01615 return incidence ? incidence->accept( *this ) : false;
01616 }
01617 QString result() const { return mResult; }
01618
01619 protected:
01620 bool visit( Event *event );
01621 bool visit( Todo *todo );
01622 bool visit( Journal *journal );
01623 bool visit( FreeBusy *fb );
01624
01625 QString dateRangeText( Event*event );
01626 QString dateRangeText( Todo *todo );
01627 QString dateRangeText( Journal *journal );
01628 QString dateRangeText( FreeBusy *fb );
01629
01630 QString generateToolTip( Incidence* incidence, QString dtRangeText );
01631
01632 protected:
01633 bool mRichText;
01634 QString mResult;
01635 };
01636
01637 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Event*event )
01638 {
01639 QString ret;
01640 QString tmp;
01641 if ( event->isMultiDay() ) {
01642
01643 tmp = "<br>" + i18n("Event start", "<i>From:</i> %1");
01644 if (event->doesFloat())
01645 ret += tmp.arg( event->dtStartDateStr().replace(" ", " ") );
01646 else
01647 ret += tmp.arg( event->dtStartStr().replace(" ", " ") );
01648
01649 tmp = "<br>" + i18n("Event end","<i>To:</i> %1");
01650 if (event->doesFloat())
01651 ret += tmp.arg( event->dtEndDateStr().replace(" ", " ") );
01652 else
01653 ret += tmp.arg( event->dtEndStr().replace(" ", " ") );
01654
01655 } else {
01656
01657 ret += "<br>"+i18n("<i>Date:</i> %1").
01658 arg( event->dtStartDateStr().replace(" ", " ") );
01659 if ( !event->doesFloat() ) {
01660 if ( event->dtStartTimeStr() == event->dtEndTimeStr() ) {
01661 tmp = "<br>" + i18n("time for event, to prevent ugly line breaks",
01662 "<i>Time:</i> %1").
01663 arg( event->dtStartTimeStr().replace(" ", " ") );
01664 } else {
01665 tmp = "<br>" + i18n("time range for event, to prevent ugly line breaks",
01666 "<i>Time:</i> %1 - %2").
01667 arg( event->dtStartTimeStr().replace(" ", " ") ).
01668 arg( event->dtEndTimeStr().replace(" ", " ") );
01669 }
01670 ret += tmp;
01671 }
01672
01673 }
01674 return ret;
01675 }
01676
01677 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Todo*todo )
01678 {
01679 QString ret;
01680 bool floats( todo->doesFloat() );
01681 if (todo->hasStartDate())
01682
01683
01684
01685 ret += "<br>" + i18n("<i>Start:</i> %1").arg(
01686 (floats)
01687 ?(todo->dtStartDateStr().replace(" ", " "))
01688 :(todo->dtStartStr().replace(" ", " ")) ) ;
01689 if (todo->hasDueDate())
01690 ret += "<br>" + i18n("<i>Due:</i> %1").arg(
01691 (floats)
01692 ?(todo->dtDueDateStr().replace(" ", " "))
01693 :(todo->dtDueStr().replace(" ", " ")) );
01694 if (todo->isCompleted())
01695 ret += "<br>" + i18n("<i>Completed:</i> %1").arg( todo->completedStr().replace(" ", " ") );
01696 else
01697 ret += "<br>" + i18n("%1 % completed").arg(todo->percentComplete());
01698
01699 return ret;
01700 }
01701
01702 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( Journal*journal )
01703 {
01704 QString ret;
01705 if (journal->dtStart().isValid() ) {
01706 ret += "<br>" + i18n("<i>Date:</i> %1").arg( journal->dtStartDateStr( false ) );
01707 }
01708 return ret;
01709 }
01710
01711 QString IncidenceFormatter::ToolTipVisitor::dateRangeText( FreeBusy *fb )
01712 {
01713 QString tmp( "<br>" + i18n("<i>Period start:</i> %1") );
01714 QString ret = tmp.arg( KGlobal::locale()->formatDateTime( fb->dtStart() ) );
01715 tmp = "<br>" + i18n("<i>Period start:</i> %1");
01716 ret += tmp.arg( KGlobal::locale()->formatDateTime( fb->dtEnd() ) );
01717 return ret;
01718 }
01719
01720
01721
01722 bool IncidenceFormatter::ToolTipVisitor::visit( Event *event )
01723 {
01724 mResult = generateToolTip( event, dateRangeText( event ) );
01725 return !mResult.isEmpty();
01726 }
01727
01728 bool IncidenceFormatter::ToolTipVisitor::visit( Todo *todo )
01729 {
01730 mResult = generateToolTip( todo, dateRangeText( todo ) );
01731 return !mResult.isEmpty();
01732 }
01733
01734 bool IncidenceFormatter::ToolTipVisitor::visit( Journal *journal )
01735 {
01736 mResult = generateToolTip( journal, dateRangeText( journal ) );
01737 return !mResult.isEmpty();
01738 }
01739
01740 bool IncidenceFormatter::ToolTipVisitor::visit( FreeBusy *fb )
01741 {
01742 mResult = "<qt><b>" + i18n("Free/Busy information for %1")
01743 .arg(fb->organizer().fullName()) + "</b>";
01744 mResult += dateRangeText( fb );
01745 mResult += "</qt>";
01746 return !mResult.isEmpty();
01747 }
01748
01749 QString IncidenceFormatter::ToolTipVisitor::generateToolTip( Incidence* incidence, QString dtRangeText )
01750 {
01751 if ( !incidence )
01752 return QString::null;
01753
01754 QString tmp = "<qt><b>"+ incidence->summary().replace("\n", "<br>")+"</b>";
01755
01756 tmp += dtRangeText;
01757
01758 if (!incidence->location().isEmpty()) {
01759
01760 tmp += "<br>"+i18n("<i>Location:</i> %1").
01761 arg( incidence->location().replace("\n", "<br>") );
01762 }
01763 if (!incidence->description().isEmpty()) {
01764 QString desc(incidence->description());
01765 if (desc.length()>120) {
01766 desc = desc.left(120) + "...";
01767 }
01768 tmp += "<br>----------<br>" + i18n("<i>Description:</i><br>") + desc.replace("\n", "<br>");
01769 }
01770 tmp += "</qt>";
01771 return tmp;
01772 }
01773
01774 QString IncidenceFormatter::toolTipString( IncidenceBase *incidence, bool richText )
01775 {
01776 ToolTipVisitor v;
01777 if ( v.act( incidence, richText ) ) {
01778 return v.result();
01779 } else
01780 return QString::null;
01781 }
01782
01783
01784
01785
01786
01787
01788
01789
01790 class IncidenceFormatter::MailBodyVisitor : public IncidenceBase::Visitor
01791 {
01792 public:
01793 MailBodyVisitor() : mResult( "" ) {}
01794
01795 bool act( IncidenceBase *incidence )
01796 {
01797 mResult = "";
01798 return incidence ? incidence->accept( *this ) : false;
01799 }
01800 QString result() const { return mResult; }
01801
01802 protected:
01803 bool visit( Event *event );
01804 bool visit( Todo *todo );
01805 bool visit( Journal *journal );
01806 bool visit( FreeBusy * ) { mResult = i18n("This is a Free Busy Object"); return !mResult.isEmpty(); }
01807 protected:
01808 QString mResult;
01809 };
01810
01811
01812 static QString mailBodyIncidence( Incidence *incidence )
01813 {
01814 QString body;
01815 if ( !incidence->summary().isEmpty() ) {
01816 body += i18n("Summary: %1\n").arg( incidence->summary() );
01817 }
01818 if ( !incidence->organizer().isEmpty() ) {
01819 body += i18n("Organizer: %1\n").arg( incidence->organizer().fullName() );
01820 }
01821 if ( !incidence->location().isEmpty() ) {
01822 body += i18n("Location: %1\n").arg( incidence->location() );
01823 }
01824 return body;
01825 }
01826
01827 bool IncidenceFormatter::MailBodyVisitor::visit( Event *event )
01828 {
01829 QString recurrence[]= {i18n("no recurrence", "None"),
01830 i18n("Minutely"), i18n("Hourly"), i18n("Daily"),
01831 i18n("Weekly"), i18n("Monthly Same Day"), i18n("Monthly Same Position"),
01832 i18n("Yearly"), i18n("Yearly"), i18n("Yearly")};
01833
01834 mResult = mailBodyIncidence( event );
01835 mResult += i18n("Start Date: %1\n").arg( event->dtStartDateStr() );
01836 if ( !event->doesFloat() ) {
01837 mResult += i18n("Start Time: %1\n").arg( event->dtStartTimeStr() );
01838 }
01839 if ( event->dtStart() != event->dtEnd() ) {
01840 mResult += i18n("End Date: %1\n").arg( event->dtEndDateStr() );
01841 }
01842 if ( !event->doesFloat() ) {
01843 mResult += i18n("End Time: %1\n").arg( event->dtEndTimeStr() );
01844 }
01845 if ( event->doesRecur() ) {
01846 Recurrence *recur = event->recurrence();
01847
01848 mResult += i18n("Recurs: %1\n")
01849 .arg( recurrence[ recur->recurrenceType() ] );
01850 mResult += i18n("Frequency: %1\n")
01851 .arg( event->recurrence()->frequency() );
01852
01853 if ( recur->duration() > 0 ) {
01854 mResult += i18n ("Repeats once", "Repeats %n times", recur->duration());
01855 mResult += '\n';
01856 } else {
01857 if ( recur->duration() != -1 ) {
01858
01859 QString endstr;
01860 if ( event->doesFloat() ) {
01861 endstr = KGlobal::locale()->formatDate( recur->endDate() );
01862 } else {
01863 endstr = KGlobal::locale()->formatDateTime( recur->endDateTime() );
01864 }
01865 mResult += i18n("Repeat until: %1\n").arg( endstr );
01866 } else {
01867 mResult += i18n("Repeats forever\n");
01868 }
01869 }
01870 }
01871 QString details = event->description();
01872 if ( !details.isEmpty() ) {
01873 mResult += i18n("Details:\n%1\n").arg( details );
01874 }
01875 return !mResult.isEmpty();
01876 }
01877
01878 bool IncidenceFormatter::MailBodyVisitor::visit( Todo *todo )
01879 {
01880 mResult = mailBodyIncidence( todo );
01881
01882 if ( todo->hasStartDate() ) {
01883 mResult += i18n("Start Date: %1\n").arg( todo->dtStartDateStr() );
01884 if ( !todo->doesFloat() ) {
01885 mResult += i18n("Start Time: %1\n").arg( todo->dtStartTimeStr() );
01886 }
01887 }
01888 if ( todo->hasDueDate() ) {
01889 mResult += i18n("Due Date: %1\n").arg( todo->dtDueDateStr() );
01890 if ( !todo->doesFloat() ) {
01891 mResult += i18n("Due Time: %1\n").arg( todo->dtDueTimeStr() );
01892 }
01893 }
01894 QString details = todo->description();
01895 if ( !details.isEmpty() ) {
01896 mResult += i18n("Details:\n%1\n").arg( details );
01897 }
01898 return !mResult.isEmpty();
01899 }
01900
01901 bool IncidenceFormatter::MailBodyVisitor::visit( Journal *journal )
01902 {
01903 mResult = mailBodyIncidence( journal );
01904 mResult += i18n("Date: %1\n").arg( journal->dtStartDateStr() );
01905 if ( !journal->doesFloat() ) {
01906 mResult += i18n("Time: %1\n").arg( journal->dtStartTimeStr() );
01907 }
01908 if ( !journal->description().isEmpty() )
01909 mResult += i18n("Text of the journal:\n%1\n").arg( journal->description() );
01910 return !mResult.isEmpty();
01911 }
01912
01913
01914
01915 QString IncidenceFormatter::mailBodyString( IncidenceBase *incidence )
01916 {
01917 if ( !incidence )
01918 return QString::null;
01919
01920 MailBodyVisitor v;
01921 if ( v.act( incidence ) ) {
01922 return v.result();
01923 }
01924 return QString::null;
01925 }