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