kmail Library API Documentation

kmgroupware.cpp

00001 /*
00002     kmgroupware.cpp
00003 
00004     This file is part of KMail.
00005 
00006     Copyright (c) 2003 Bo Thorsen <bo@klaralvdalens-datakonsult.se>
00007     Copyright (c) 2002 Karl-Heinz Zimmer <khz@klaralvdalens-datakonsult.se>
00008     Copyright (c) 2003 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
00009 
00010     This library is free software; you can redistribute it and/or
00011     modify it under the terms of the GNU Library General Public
00012     License as published by the Free Software Foundation; either
00013     version 2 of the License, or (at your option) any later version.
00014 
00015     This library is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018     Library General Public License for more details.
00019 
00020     You should have received a copy of the GNU Library General Public License
00021     along with this library; see the file COPYING.LIB.  If not, write to
00022     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00023     Boston, MA 02111-1307, USA.
00024 */
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #include <config.h>
00028 #endif
00029 
00030 #include "kmgroupware.h"
00031 
00032 #include "kfileio.h"
00033 #include "kmmainwin.h"
00034 #include "kmmainwidget.h"
00035 #include "kmfoldermgr.h"
00036 #include "kmfoldertree.h"
00037 #include "kmcomposewin.h"
00038 #include "kmidentity.h"
00039 #include "identitymanager.h"
00040 #include "kmacctmgr.h"
00041 #include "kmgroupwarefuncs.h"
00042 #include "kmcommands.h"
00043 #include "kmfolderindex.h"
00044 #include "kmkernel.h"
00045 #include "objecttreeparser.h"
00046 #include "kmailicalifaceimpl.h"
00047 
00048 using KMail::ObjectTreeParser;
00049 
00050 #include <libkcal/icalformat.h>
00051 #include <libkcal/calendarlocal.h>
00052 #include <libkcal/event.h>
00053 
00054 using namespace KCal;
00055 
00056 #include <kabc/addressee.h>
00057 #include <kabc/address.h>
00058 #include <kabc/phonenumber.h>
00059 #include <kabc/vcardconverter.h>
00060 
00061 using namespace KABC;
00062 
00063 #include <ktnef/ktnefparser.h>
00064 #include <ktnef/ktnefmessage.h>
00065 #include <ktnef/ktnefdefs.h>
00066 
00067 #include <kurl.h>
00068 #include <kmessagebox.h>
00069 #include <klibloader.h>
00070 #include <dcopclient.h>
00071 #include <kparts/part.h>
00072 #include <kconfig.h>
00073 #include <kapplication.h>
00074 #include <kinputdialog.h>
00075 
00076 #include <kdebug.h>
00077 
00078 #include <qregexp.h>
00079 #include <qbuffer.h>
00080 #include <qfile.h>
00081 
00082 #include <mimelib/enum.h>
00083 #include <mimelib/headers.h>
00084 #include <mimelib/bodypart.h>
00085 #include <mimelib/string.h>
00086 #include <mimelib/text.h>
00087 
00088 #include <assert.h>
00089 
00090 //-----------------------------------------------------------------------------
00091 KMGroupware::KMGroupware( QObject* parent, const char* name )
00092   : QObject( parent, name ), mUseGroupware( false ), mMainWidget( 0 )
00093 {
00094 }
00095 
00096 //-----------------------------------------------------------------------------
00097 KMGroupware::~KMGroupware()
00098 {
00099 }
00100 
00101 void KMGroupware::readConfig()
00102 {
00103   KConfigGroup options( KMKernel::config(), "Groupware" );
00104 
00105   // Do not read the config for this, if it's not setup at all
00106   if( options.readEntry( "Enabled", "notset" ) == "notset" )
00107     return;
00108 
00109   mUseGroupware = options.readBoolEntry( "Enabled", true );
00110 }
00111 
00112 bool KMGroupware::vPartFoundAndDecoded( KMMessage* msg, QString& s )
00113 {
00114   assert( msg );
00115 
00116   if( ( DwMime::kTypeText == msg->type() && ( DwMime::kSubtypeVCal   == msg->subtype() ||
00117                           DwMime::kSubtypeXVCard == msg->subtype() ) ) ||
00118       ( DwMime::kTypeApplication == msg->type() &&
00119     DwMime::kSubtypeOctetStream == msg->subtype() ) )
00120   {
00121     s = QString::fromUtf8( msg->bodyDecoded() );
00122     return true;
00123   } else if( DwMime::kTypeMultipart == msg->type() &&
00124         (DwMime::kSubtypeMixed  == msg->subtype() ) ||
00125         (DwMime::kSubtypeAlternative  == msg->subtype() ))
00126   {
00127     // kdDebug(5006) << "KMGroupware looking for TNEF data" << endl;
00128     DwBodyPart* dwPart = msg->findDwBodyPart( DwMime::kTypeApplication,
00129                           DwMime::kSubtypeMsTNEF );
00130     if( !dwPart )
00131       dwPart = msg->findDwBodyPart( DwMime::kTypeApplication,
00132                     DwMime::kSubtypeOctetStream );
00133     if( dwPart ){
00134       // kdDebug(5006) << "KMGroupware analyzing TNEF data" << endl;
00135       KMMessagePart msgPart;
00136       KMMessage::bodyPart(dwPart, &msgPart);
00137       return KMGroupware::msTNEFToVPart( msgPart.bodyDecodedBinary(), s );
00138     }
00139     else {
00140         dwPart = msg->findDwBodyPart( DwMime::kTypeText,
00141                 DwMime::kSubtypeVCal );
00142         if (dwPart) {
00143             KMMessagePart msgPart;
00144         KMMessage::bodyPart(dwPart, &msgPart);
00145         s = msgPart.body();
00146         return true;
00147         }
00148     }
00149   }else if( DwMime::kTypeMultipart == msg->type() &&
00150         DwMime::kSubtypeMixed  == msg->subtype() ){
00151   }
00152 
00153   return false;
00154 }
00155 
00156 
00157 //-----------------------------------------------------------------------------
00158 //   Special Contacts methods called by KMKernel's DCOP functions
00159 //-----------------------------------------------------------------------------
00160 void KMGroupware::requestAddresses( QString fname )
00161 {
00162   QFile file( fname );
00163   if( file.open( IO_WriteOnly ) ) {
00164     QTextStream ts( &file );
00165     ts.setEncoding( QTextStream::UnicodeUTF8 );
00166 
00167     KMFolder* contacts = kmkernel->iCalIface().folderFromType( "Contact" );
00168     if( contacts ) {
00169       QString s;
00170       for( int i=0; i<contacts->count(); ++i ) {
00171         bool unget = !contacts->isMessage(i);
00172         if( KMGroupware::vPartFoundAndDecoded( contacts->getMsg( i ), s ) ) {
00173           ts << s;
00174           s.replace('\n', "\\n");
00175           s.truncate(65);
00176         }
00177         if( unget ) contacts->unGetMsg(i);
00178       }
00179     }else {
00180       kdDebug(5006) << "+++KMGroupware::requestAddresses(): Contacts folder does not exist" << endl;
00181     }
00182     file.close();
00183   }else {
00184     kdDebug(5006) << "+++KMGroupware::requestAddresses(): could not open file" << endl;
00185   }
00186 }
00187 
00188 //--------------
00189 bool KMGroupware::storeAddresses( QString fname, QStringList delUIDs )
00190 {
00191   KMFolder* contacts = kmkernel->iCalIface().folderFromType( "Contact" );
00192   if( !contacts ) {
00193     kdDebug(5006) << "KMGroupware::storeAddresses(): Contacts folder does not exist" << endl;
00194     return false;
00195   }
00196 
00197   QFile file( fname );
00198   QStringList vCards;
00199   if( file.open( IO_ReadOnly ) ) {
00200     QTextStream ts( &file );
00201     ts.setEncoding( QTextStream::UnicodeUTF8 );
00202     QString currentVCard;
00203     while( !ts.eof() ) {
00204       QString line;
00205       line = ts.readLine();
00206       if( line.isEmpty() ) {
00207     // New vCard
00208     vCards << currentVCard;
00209     currentVCard = "";
00210       } else {
00211     // Continue current vCard
00212     currentVCard += line + "\r\n";
00213       }
00214     }
00215     file.close();
00216   }else{
00217     kdDebug(5006) << "KMGroupware::storeAddresses(): could not open file" << endl;
00218     return false;
00219   }
00220 
00221   for( QStringList::iterator it = delUIDs.begin(); it != delUIDs.end(); ++it ) {
00222     KMMessage* msg = kmkernel->iCalIface().findMessageByUID( *it, contacts );
00223     if( msg )
00224       kmkernel->iCalIface().deleteMsg( msg );
00225     else
00226       kdDebug(5006) << "vCard not found, cannot remove: " << *it << endl;
00227   }
00228 
00229   for( QStringList::iterator it2 = vCards.begin(); it2 != vCards.end(); ++it2 ) {
00230     QCString vCard( (*it2).utf8() );
00231     QString uid( "UID" );
00232     QString name( "NAME" );
00233     vPartMicroParser( vCard, uid, name );
00234     KMMessage* msg = kmkernel->iCalIface().findMessageByUID( uid, contacts );
00235     if( !msg ) {
00236       // This is a new vCard, make a message to store it in
00237       msg = new KMMessage(); // makes a "Content-Type=text/plain" message
00238       msg->initHeader();
00239       msg->setType( DwMime::kTypeText );
00240       msg->setSubtype( DwMime::kSubtypeXVCard );
00241       msg->setHeaderField( "Content-Type", "Text/X-VCard; charset=\"utf-8\"" );
00242       msg->setSubject( "Contact" );
00243       msg->setTo( name );
00244 
00245       // add missing headers/content:
00246       msg->setBodyEncoded( vCard );
00247 
00248       // mark the message as read and store it in our Contacts folder
00249       msg->touch();
00250       contacts->addMsg( msg );
00251     } else {
00252       // Figure out if the contact have been changed
00253       QString s;
00254       if( vPartFoundAndDecoded( msg, s ) && s.utf8() != vCard ) {
00255     msg->setBodyEncoded( vCard );
00256     msg->setTo( name );
00257       }
00258     }
00259   }
00260   return true;
00261 }
00262 
00263 
00264 KMGroupware::VCalType KMGroupware::getVCalType( const QString &vCal )
00265 {
00266   // This is ugly: We can't even use vPartMicroParser() here, because
00267   // we are actually looking for the _second_ BEGIN: line.
00268   // PENDING(kalle) We might need to look for even more things here,
00269   // like journals.
00270   if( vCal.find( QRegExp( "BEGIN:\\s*VEVENT" ) ) != -1 )
00271     return vCalEvent;
00272   else if( vCal.find( QRegExp( "BEGIN:\\s*VTODO" ) ) != -1 )
00273     return vCalTodo;
00274   return vCalUnknown;
00275 }
00276 
00277 //-----------------------------------------------------------------------------
00278 void KMGroupware::processVCalRequest( const QCString& receiver,
00279                       const QString& vCalIn,
00280                                       QString& choice )
00281 {
00282 #if 0
00283   // FIXME: Reinstate Outlook workaround
00284   // If we are in legacy mode, and there is more than one receiver, we
00285   // need to ask the user which address to use
00286   KMMessage* msgOld = mMainWidget->headers()->currentMsg();
00287   KConfigGroup options( KMKernel::config(), "Groupware" );
00288   QString fromAddress; // this variable is only used in legacy mode
00289   if( options.readBoolEntry( "LegacyMangleFromToHeaders", false ) ) {
00290       QStringList toAddresses = KMMessage::splitEmailAddrList( msgOld->to() );
00291       if( toAddresses.count() <= 1 )
00292           // only one address: no problem, we can spare the user the dialog
00293           // and just take the from address
00294           fromAddress = msgOld->to();
00295       else {
00296           // We have more than one To: address and are in legacy mode. Next
00297           // try is to search the identities for one of the email addresses
00298           // in the toAddresses list.
00299           for( QStringList::Iterator sit = toAddresses.begin();
00300                sit != toAddresses.end(); ++sit ) {
00301               if( KMMessage::getEmailAddr( *sit ) ==
00302                   kmkernel->identityManager()->defaultIdentity().emailAddr().local8Bit() ) {
00303                   // our default identity was contained in the To: list,
00304                   // copy that from To: to From:
00305                   fromAddress = *sit;
00306                   break; // We are done
00307               }
00308           }
00309 
00310           // If we still haven't found anything, we have to ask the user
00311           // what to do.
00312           if( fromAddress.isEmpty() ) {
00313               bool bOk;
00314               fromAddress = KInputDialog::getItem( i18n( "Select Address" ),
00315                                                    i18n( "In order to let Outlook(tm) recognize you as the receiver, you need to indicate which one of the following addresses is your email address:" ),
00316                                                    toAddresses, 0, false, &bOk,
00317                                                    kmkernel->mainWin() );
00318               if( !bOk )
00319                   // If the user didn't select anything, just take the
00320                   // first one so that we have something at all.
00321                   fromAddress = toAddresses.first();
00322           }
00323       }
00324   }
00325 #endif
00326 
00327   QByteArray data, replyData;
00328   QCString replyType;
00329   QDataStream arg( data, IO_WriteOnly );
00330   arg << choice << receiver << vCalIn;
00331   if( kapp->dcopClient()->call( "korganizer", "KOrganizerIface",
00332                 "eventRequest(QString,QCString,QString)",
00333                 data, replyType, replyData )
00334       && replyType == "bool" )
00335   {
00336     bool rc;
00337     QDataStream replyStream( replyData, IO_ReadOnly );
00338     replyStream >> rc;
00339     kdDebug(5006) << "KOrganizer call succeeded, rc = " << rc << endl;
00340 
00341     if( rc && mMainWidget ) mMainWidget->slotTrashMsg();
00342   } else
00343     kdDebug(5006) << "KOrganizer call failed";
00344 }
00345 
00346 
00347 //-----------------------------------------------------------------------------
00348 void KMGroupware::processVCalReply( const QCString& sender,
00349                     const QString& vCal,
00350                                     const QString& choice )
00351 {
00352   VCalType type = getVCalType( vCal );
00353   if( type == vCalUnknown ) {
00354     kdDebug(5006) << "processVCalReply called with something that is not a vCal\n";
00355     return;
00356   }
00357 
00358   if( choice == "enter" ) {
00359     // step 1: call Organizer
00360     QByteArray data, replyData;
00361     QCString replyType;
00362     QDataStream arg( data, IO_WriteOnly );
00363     arg << sender << vCal;
00364     if( kapp->dcopClient()->call( "korganizer", "KOrganizerIface",
00365                   "eventReply(QCString,QString)",
00366                   data, replyType, replyData )
00367     && replyType == "bool" )
00368     {
00369       bool rc;
00370       QDataStream replyStream( replyData, IO_ReadOnly );
00371       replyStream >> rc;
00372       kdDebug(5006) << "KOrganizer call succeeded, rc = " << rc << endl;
00373 
00374       if( rc )
00375     kdDebug(5006) << "KOrganizer call succeeded\n";
00376     } else
00377       kdDebug(5006) << "KOrganizer call failed\n";
00378 
00379     // step 2: inform user that Organizer was updated
00380     KMessageBox::information( kmkernel->mainWin(), (type == vCalEvent ?
00381                      i18n("The answer was registered in your calendar.") :
00382                      i18n("The answer was registered in your task list.")),
00383                   QString::null, "groupwareBox");
00384   } else if( choice == "cancel" ) {
00385 #if 0
00386     // TODO: Implement this with DCOP
00387     QString uid( "UID" );
00388     QString descr("DESCRIPTION");
00389     QString summary("SUMMARY");
00390 
00391     vPartMicroParser( vCal.utf8(), uid, descr, summary );
00392     if( type == vCalEvent ) {
00393       emit signalEventDeleted( uid );
00394       KMessageBox::information( kmkernel->mainWin(), i18n("<qt>The event <b>%1</b> was deleted from your calendar.</qt>")
00395                 .arg( descr) );
00396     } else if( type == vCalTodo ) {
00397       emit signalTaskDeleted( uid );
00398       KMessageBox::information( kmkernel->mainWin(), i18n("The task was deleted from your tasks")
00399                 .arg( summary ) );
00400     }
00401 #endif
00402   } else {
00403     // Don't know what to do, so better not delete the mail
00404     return;
00405   }
00406 
00407   // An answer was saved, so trash the message
00408   if( mMainWidget ) mMainWidget->slotTrashMsg();
00409 }
00410 
00411 
00412 //-----------------------------------------------------------------------------
00413 bool KMGroupware::vPartToHTML( int /*aUpdateCounter*/, const QString& vCal,
00414                    QString fname, QString& prefix,
00415                    QString& postfix ) const
00416 {
00417   VCalType type = getVCalType( vCal );
00418   if( type == vCalUnknown ) {
00419     kdDebug(5006) << "Unknown incidence!\n";
00420     return false;
00421   }
00422 
00423   CalendarLocal cl;
00424   ICalFormat format;
00425   format.fromString(&cl, vCal);
00426   // make a shallow copy of the event list
00427   Event::List eventList = cl.events();
00428   // the events will be deleted automatically when cl is destroyed
00429   eventList.setAutoDelete(false);
00430 
00431   if( eventList.count() == 0 )
00432     // This could be a task
00433     // TODO: Handle tasks
00434     return false;
00435 
00436   // parse the first event out of the vcal
00437   // ### is it legal to have several events per mail?
00438   Event* event = eventList.first();
00439   QString sLocation = event->location();
00440   QString sDtEnd = event->dtEndTimeStr();
00441   QString sDtStart = event->dtStartTimeStr();
00442   QString sDescr = event->description().simplifyWhiteSpace();
00443   QString sMethod; // = event->method(); //###TODO actually the scheduler needs to do that
00444 
00445   QString sAttendee;
00446   Attendee::List attendees = event->attendees();
00447   if( attendees.count() == 0 ) {
00448     kdDebug(5006) << "No attendees in the iCal!\n";
00449     return false;
00450   }
00451   if( attendees.count() != 1 )
00452     kdDebug(5006) << "Warning: attendeecount in the reply should be 1 but is "
00453           << attendees.count() << endl;
00454   Attendee* attendee = *attendees.begin();
00455 
00456   // FIXME: This is a temporary workaround to get the method
00457   sMethod = "METHOD";
00458   vPartMicroParser( vCal.utf8(), sMethod );
00459 
00460   QString sSummary = event->summary();
00461 
00462   kdDebug(5006) << "Event stuff: " << sLocation << ", " << sDtEnd << ", "
00463         << sDtStart << ", " << sDescr << ", " << sMethod << ", "
00464         << sAttendee << endl;
00465 
00466   string2HTML( sLocation );
00467   string2HTML( sDescr );
00468 
00469   sMethod = sMethod.lower();
00470 
00471   QString typeString;
00472   if( type == vCalEvent )
00473     typeString = i18n("calendar");
00474   else
00475     typeString = i18n("tasks");
00476 
00477   if( sMethod == "request" ) {
00478     if( type == vCalEvent ) {
00479       prefix = i18n("You have been invited to a meeting");
00480       prefix += "<br>";
00481       if( !sLocation.isEmpty() )
00482     prefix.append( i18n( "The meeting will take place in %1 from %2 to %3" )
00483                .arg( sLocation ).arg( sDtStart ).arg( sDtEnd ) );
00484       else
00485     prefix.append( i18n( "The meeting will take place from %1 to %2" )
00486                .arg( sDtStart )
00487                .arg( sDtEnd ) );
00488     } else {
00489       prefix = i18n( "You have been assigned a task:<br>%1" ).arg( sSummary );
00490     }
00491   } else if( sMethod == "reply" ) {
00492     switch( attendee->status() ) {
00493     case Attendee::Accepted:
00494       if( type == vCalEvent )
00495     prefix = i18n("Sender <b>accepts</b> the invitation to meet in %1<br>from %2 to %3.")
00496       .arg( sLocation ).arg( sDtStart ).arg( sDtEnd );
00497       else if( type == vCalTodo )
00498     prefix = i18n( "Sender <b>accepts</b> the task <b>%1</b>." ).arg(sSummary );
00499       break;
00500 
00501     case Attendee::Tentative:
00502       if( type == vCalEvent )
00503     prefix = i18n("Sender <b>tentatively accepts</b> the invitation to meet in %1<br>from %2 to %3.")
00504       .arg( sLocation ).arg( sDtStart ).arg( sDtEnd );
00505       else if( type == vCalTodo )
00506     prefix = i18n( "Sender <b>tentatively accepts</b> the task <b>%1</b>." ).
00507       arg(sSummary );
00508       break;
00509 
00510     case Attendee::Declined:
00511       if( type == vCalEvent )
00512     prefix = i18n("Sender <b>declines</b> the invitation to meet in %1<br>from %2 to %3.")
00513       .arg( sLocation ).arg( sDtStart ).arg( sDtEnd );
00514       else if( vCalTodo )
00515     prefix = i18n( "Sender <b>declines</b> the task %1." ).arg( sSummary );
00516       break;
00517 
00518     default:
00519       if( type == vCalEvent ) {
00520     prefix = i18n("This is an unknown reply to the event in %1 from %2 to %3")
00521       .arg( sLocation ).arg( sDtStart ).arg( sDtEnd );
00522       } else if( type == vCalTodo ) {
00523     prefix = i18n("This is an unknown reply to the task %1").arg(sSummary);
00524       }
00525     }
00526   } else if( sMethod == "cancel" ) {
00527     if( type == vCalEvent ) {
00528       prefix = i18n("The event %1 was canceled").arg(sSummary);
00529     } else if( type == vCalTodo ) {
00530       prefix = i18n("The task %1 was canceled").arg(sSummary);
00531     }
00532   }
00533 
00534   // show the 'buttons' (only if in groupware mode)
00535   // Disable buttons. This is handled in KOrganizer.
00536   if( false && mUseGroupware ) {
00537     prefix.append( "<br>&nbsp;<br>&nbsp;<br><table border=\"0\" cellspacing=\"0\"><tr><td>&nbsp;</td><td>" );
00538     if( sMethod == "request" || sMethod == "update" ) {
00539       // Accept
00540       prefix.append( QString("<a href=\"kmail:groupware_vCal_request_accept#%1\"><b>")
00541              .arg(fname) );
00542       prefix.append( i18n("[Accept]") );
00543       prefix.append( QString("</b></a></td><td> &nbsp; </td><td>") );
00544       // Accept conditionally
00545       prefix.append( QString("<a href=\"kmail:groupware_vCal_request_accept conditionally#%1\"><b>")
00546              .arg( fname ) );
00547       prefix.append( i18n("[Accept&nbsp;cond.]") );
00548       prefix.append( QString("</b></a></td><td> &nbsp; </td><td>") );
00549       // Decline
00550       prefix.append( QString("<a href=\"kmail:groupware_vCal_request_decline#%1\"><b>")
00551              .arg( fname ) );
00552       prefix.append( i18n("[Decline]") );
00553       prefix.append( QString("</b></a></td><td> &nbsp; </td><td>" ) );
00554       if( type == vCalEvent ) {
00555     // Check my calendar...
00556     prefix.append(QString("<a href=\"kmail:groupware_vCal_request_check#%1\"><b>")
00557               .arg(fname));
00558     prefix.append(i18n("[Check&nbsp;my&nbsp;calendar...]"));
00559     prefix.append(QString("</b></a>"));
00560       }
00561     } else if( sMethod == "reply" ) {
00562       // Enter this into my calendar
00563       prefix.append(QString("<a href=\"kmail:groupware_vCal_reply_enter#%1\"><b>")
00564             .arg(fname));
00565       if( type == vCalEvent )
00566     prefix.append(i18n("[Enter&nbsp;this&nbsp;into&nbsp;my&nbsp;calendar]"));
00567       else
00568     prefix.append(i18n("[Enter&nbsp;this&nbsp;into&nbsp;my&nbsp;tasks]"));
00569       prefix.append(QString("</b></a>"));
00570     } else if( sMethod == "cancel" ) {
00571       // Cancel event from my calendar
00572       prefix.append( QString("<a href=\"kmail:groupware_vCal_cancel_enter#%1\"><b>")
00573              .arg( fname ) );
00574       prefix.append( i18n("[Remove&nbsp;this&nbsp;from&nbsp;my&nbsp;calendar]"));
00575       prefix.append(QString("</b></a>"));
00576     }
00577     prefix.append( "</td></tr></table>" );
00578   }
00579 
00580   if( sMethod == "request" || sMethod == "cancel" ) {
00581     sDescr.prepend( "<br>&nbsp;<br>&nbsp;<br><u>" + i18n("Description:")
00582             + "</u><br><table border=\"0\"><tr><td>&nbsp;</td><td>" );
00583     sDescr.append( "</td></tr></table>" );
00584     prefix.append( sDescr );
00585   }
00586   prefix.append("&nbsp;<br>&nbsp;<br><u>");
00587   prefix.append(i18n("Original message:"));
00588   prefix.append("</u><br><table border=\"0\"><tr><td>&nbsp;</td><td>");
00589   // postfix:
00590   postfix = "</td></tr></table>";
00591 
00592   return true;
00593 }
00594 
00595 
00596 //-----------------------------------------------------------------------------
00597 
00598 QString stringProp( KTNEFMessage* tnefMsg, const Q_UINT32& key,
00599                     const QString& fallback = QString::null)
00600 {
00601   return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16, fallback );
00602 }
00603 
00604 QString sNamedProp( KTNEFMessage* tnefMsg, const QString& name,
00605                     const QString& fallback = QString::null)
00606 {
00607   return tnefMsg->findNamedProp( name, fallback );
00608 }
00609 
00610 //-----------------------------------------------------------------------------
00611 
00612 bool KMGroupware::msTNEFToVPart( const QByteArray& tnef, QString& vPart )
00613 {
00614   // Note: vPart is not erased but
00615   //       keeps it's initial data if it cannot be decoded
00616   bool bOk = false;
00617 
00618   KTNEFParser parser;
00619   QBuffer buf( tnef );
00620   CalendarLocal cal;
00621   Addressee addressee;
00622   VCardConverter cardConv;
00623   ICalFormat calFormat;
00624   Event* event = new Event();
00625 
00626   if( parser.openDevice( &buf ) )
00627   {
00628     KTNEFMessage* tnefMsg = parser.message();
00629     //QMap<int,KTNEFProperty*> props = parser.message()->properties();
00630 
00631     // everything depends from property PR_MESSAGE_CLASS
00632     // (this is added by KTNEFParser):
00633     QString msgClass = tnefMsg->findProp(0x001A, QString::null, true).upper();
00634     if( !msgClass.isEmpty() ){
00635       // Match the old class names that might be used by Outlook for
00636       // compatibility with Microsoft Mail for Windows for Workgroups 3.1.
00637       bool bCompatClassAppointment   = false;
00638       bool bCompatMethodRequest      = false;
00639       bool bCompatMethodCancled      = false;
00640       bool bCompatMethodAccepted     = false;
00641       bool bCompatMethodAcceptedCond = false;
00642       bool bCompatMethodDeclined     = false;
00643       if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ){
00644         bCompatClassAppointment = true;
00645         if( msgClass.endsWith( ".MTGREQ" ) )
00646           bCompatMethodRequest = true;
00647         if( msgClass.endsWith( ".MTGCNCL" ) )
00648           bCompatMethodCancled = true;
00649         if( msgClass.endsWith( ".MTGRESPP" ) )
00650           bCompatMethodAccepted = true;
00651         if( msgClass.endsWith( ".MTGRESPA" ) )
00652           bCompatMethodAcceptedCond = true;
00653         if( msgClass.endsWith( ".MTGRESPN" ) )
00654           bCompatMethodDeclined = true;
00655       }
00656       bool bCompatClassNote = (msgClass == "IPM.MICROSOFT MAIL.NOTE");
00657 
00658 
00659       if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ){
00660 
00661         // compose a vCal
00662         bool bIsReply = false;
00663         QString prodID;
00664         prodID += "-//Microsoft Corporation//Outlook ";
00665         prodID += tnefMsg->findNamedProp("0x8554", "9.0");
00666         prodID += "MIMEDIR/EN\n";
00667         prodID += "VERSION:2.0\n";
00668         calFormat.setApplication("Outlook", prodID);
00669 
00670         Scheduler::Method method;
00671 
00672         if( bCompatMethodRequest )
00673           method  = Scheduler::Request;
00674         else if ( bCompatMethodCancled )
00675           method = Scheduler::Cancel;
00676         else if ( bCompatMethodAccepted ||
00677                   bCompatMethodAcceptedCond ||
00678                   bCompatMethodDeclined ){
00679           method = Scheduler::Reply;
00680           bIsReply = true;
00681         }
00682         else{
00683           // pending(khz): verify whether "0x0c17" is the right tag ???
00684           //
00685           // at the moment we think there are REQUESTS and UPDATES
00686           //
00687           // but WHAT ABOUT REPLIES ???
00688           //
00689           //
00690 
00691           if( tnefMsg->findProp(0x0c17) == "1" )
00692             bIsReply = true;
00693           method = Scheduler::Request;
00694         }
00695 
00697         ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown /*???*/);
00698 
00699         QString sSenderSearchKeyEmail( tnefMsg->findProp(0x0C1D) );
00700 
00701         if( !sSenderSearchKeyEmail.isEmpty() ){
00702           int colon = sSenderSearchKeyEmail.find(':');
00703           if( sSenderSearchKeyEmail.find(':') == -1 ) // may be e.g. "SMTP:KHZ@KDE.ORG"
00704             sSenderSearchKeyEmail.remove(0, colon+1);
00705         }
00706 
00707         QString s( tnefMsg->findProp(0x0e04) );
00708         QStringList attendees = QStringList::split(';', s);
00709         if( attendees.count() ){
00710           for ( QStringList::Iterator it = attendees.begin(); it != attendees.end(); ++it ) {
00711             // skip all entries that have no '@' since these are no mail addresses
00712             if( (*it).find('@') == -1 ){
00713               s = (*it).stripWhiteSpace();
00714 
00715               Attendee *attendee = new Attendee(s,s, true);
00716               if (bIsReply) {
00717                 if (bCompatMethodAccepted)
00718                   attendee->setStatus(Attendee::Accepted);
00719                 if (bCompatMethodAcceptedCond)
00720                   attendee->setStatus(Attendee::Declined);
00721                 if (bCompatMethodDeclined)
00722                   attendee->setStatus(Attendee::Tentative);
00723               }
00724               else {
00725                 attendee->setStatus(Attendee::NeedsAction);
00726                 attendee->setRole(Attendee::ReqParticipant);
00727               }
00728               event->addAttendee(attendee);
00729             }
00730          }
00731        }
00732        else
00733        {
00734           // Oops, no attendees?
00735           // This must be old style, let us use the PR_SENDER_SEARCH_KEY.
00736           s = sSenderSearchKeyEmail;
00737           if( !s.isEmpty() ){
00738             Attendee *attendee = new Attendee(QString::null,QString::null, true);
00739             if (bIsReply) {
00740               if (bCompatMethodAccepted)
00741                 attendee->setStatus(Attendee::Accepted);
00742               if (bCompatMethodAcceptedCond)
00743                 attendee->setStatus(Attendee::Declined);
00744               if (bCompatMethodDeclined)
00745                 attendee->setStatus(Attendee::Tentative);
00746             }
00747             else {
00748               attendee->setStatus(Attendee::NeedsAction);
00749               attendee->setRole(Attendee::ReqParticipant);
00750             }
00751             event->addAttendee(attendee);
00752           }
00753         }
00754         s = tnefMsg->findProp(0x0c1f); // look for organizer property
00755         if( s.isEmpty() && !bIsReply )
00756           s = sSenderSearchKeyEmail;
00757         if( !s.isEmpty() )
00758           event->setOrganizer(s);
00759 
00760         s = tnefMsg->findProp(0x8516)
00761               .replace(QChar('-'), QString::null)
00762               .replace(QChar(':'), QString::null);
00763         event->setDtStart(QDateTime::fromString(s)); // ## Format??
00764 
00765         s = tnefMsg->findProp(0x8517)
00766               .replace(QChar('-'), QString::null)
00767               .replace(QChar(':'), QString::null);
00768 
00769         event->setDtEnd(QDateTime::fromString(s));
00770 
00771         s = tnefMsg->findProp(0x8208);
00772         event->setLocation(s);
00773 
00774         // is it OK to set this to OPAQUE always ??
00775         //vPart += "TRANSP:OPAQUE\n"; ###FIXME, portme!
00776         //vPart += "SEQUENCE:0\n";
00777 
00778         // is "0x0023" OK  -  or should we look for "0x0003" ??
00779         s = tnefMsg->findProp(0x0023);
00780         event->setUid(s);
00781 
00782         // pending(khz): is this value in local timezone ??   must it be adjusted ??
00783         // most likely this is a bug in the server or in Outlook - we ignore it for now.
00784         s = tnefMsg->findProp(0x8202)
00785               .replace(QChar('-'), QString::null)
00786               .replace(QChar(':'), QString::null);
00787         // event->setDtStamp(QDateTime::fromString(s)); // ### libkcal always uses currentDateTime()
00788 
00789 
00790 
00791         s = tnefMsg->findNamedProp("Keywords");
00792         event->setCategories(s);
00793 
00794         s = tnefMsg->findProp(0x1000);
00795         event->setDescription(s);
00796 
00797         s = tnefMsg->findProp(0x0070);
00798         event->setSummary(s);
00799 
00800 
00801         s = tnefMsg->findProp(0x0026);
00802         event->setPriority(s.toInt());
00803 
00804         // is reminder flag set ?
00805         if(!tnefMsg->findProp(0x8503).isEmpty()) {
00806 
00807           Alarm *alarm = new Alarm(event);
00808 
00809           QDateTime highNoonTime(
00810                       pureISOToLocalQDateTime( tnefMsg->findProp(0x8502)
00811                                                     .replace(QChar('-'), "")
00812                                                     .replace(QChar(':'), "") ) );
00813           QDateTime wakeMeUpTime(
00814                       pureISOToLocalQDateTime( tnefMsg->findProp(0x8560, "")
00815                                                     .replace(QChar('-'), "")
00816                                                     .replace(QChar(':'), "") ) );
00817 
00818            alarm->setTime(wakeMeUpTime);
00819 
00820            if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
00821              alarm->setStartOffset(Duration(highNoonTime, wakeMeUpTime));
00822            else
00823              // default: wake them up 15 minutes before the appointment
00824              alarm->setStartOffset(Duration(15*60));
00825              alarm->setDisplayAlarm(i18n("Reminder"));
00826 
00827           // sorry: the different action types are not known (yet)
00828           //        so we always set 'DISPLAY' (no sounds, no images...)
00829           event->addAlarm(alarm);
00830         }
00831         cal.addEvent(event);
00832         bOk = true;
00833         // we finished composing a vCal
00834 
00835       }else if( bCompatClassNote || "IPM.CONTACT" == msgClass ){
00836 
00837         addressee.setUid(stringProp(tnefMsg, attMSGID));
00838         addressee.setFormattedName(stringProp(tnefMsg, MAPI_TAG_PR_DISPLAY_NAME));
00839         addressee.insertEmail(sNamedProp(tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS),true);
00840         addressee.insertEmail(sNamedProp(tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS),false);
00841         addressee.insertEmail(sNamedProp(tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS),false);
00842         addressee.insertCustom("KADDRESSBOOK", "X-IMAddress",
00843           sNamedProp(tnefMsg, MAPI_TAG_CONTACT_IMADDRESS));
00844         addressee.insertCustom("KADDRESSBOOK", "X-SpousesName",
00845           stringProp(tnefMsg, MAPI_TAG_PR_SPOUSE_NAME));
00846         addressee.insertCustom("KADDRESSBOOK", "X-ManagersName",
00847           stringProp(tnefMsg, MAPI_TAG_PR_MANAGER_NAME));
00848         addressee.insertCustom("KADDRESSBOOK", "X-AssistantsName",
00849           stringProp(tnefMsg, MAPI_TAG_PR_ASSISTANT));
00850         addressee.insertCustom("KADDRESSBOOK", "X-Department",
00851           stringProp(tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME));
00852         addressee.insertCustom("KADDRESSBOOK", "X-Office",
00853           stringProp(tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION));
00854         addressee.insertCustom("KADDRESSBOOK", "X-Profession",
00855           stringProp(tnefMsg, MAPI_TAG_PR_PROFESSION));
00856 
00857         QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY)
00858                       .replace(QChar('-'), QString::null)
00859                       .replace(QChar(':'), QString::null);
00860 
00861         if( !s.isEmpty() )
00862           addressee.insertCustom("KADDRESSBOOK", "X-Anniversary", s);
00863 
00864         addressee.setUrl(KURL( sNamedProp(tnefMsg, MAPI_TAG_CONTACT_WEBPAGE )));
00865 
00866         // collect parts of Name entry
00867         addressee.setFamilyName(stringProp(tnefMsg, MAPI_TAG_PR_SURNAME));
00868         addressee.setGivenName(stringProp(tnefMsg, MAPI_TAG_PR_GIVEN_NAME));
00869         addressee.setAdditionalName(stringProp(tnefMsg, MAPI_TAG_PR_MIDDLE_NAME));
00870         addressee.setPrefix(stringProp(tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX));
00871         addressee.setSuffix(stringProp(tnefMsg, MAPI_TAG_PR_GENERATION));
00872 
00873         addressee.setNickName(stringProp(tnefMsg, MAPI_TAG_PR_NICKNAME));
00874         addressee.setRole(stringProp(tnefMsg, MAPI_TAG_PR_TITLE));
00875         addressee.setOrganization(stringProp(tnefMsg, MAPI_TAG_PR_COMPANY_NAME));
00876         /*
00877         the MAPI property ID of this (multiline) )field is unknown:
00878         vPart += stringProp(tnefMsg, "\n","NOTE", ... , "" );
00879         */
00880 
00881         Address adr;
00882 
00883         adr.setPostOfficeBox(stringProp(tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX));
00884         adr.setStreet(stringProp(tnefMsg,        MAPI_TAG_PR_HOME_ADDRESS_STREET));
00885         adr.setLocality(stringProp(tnefMsg,      MAPI_TAG_PR_HOME_ADDRESS_CITY));
00886         adr.setRegion(stringProp(tnefMsg,        MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE));
00887         adr.setPostalCode(stringProp(tnefMsg,    MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE));
00888         adr.setCountry(stringProp(tnefMsg,       MAPI_TAG_PR_HOME_ADDRESS_COUNTRY));
00889         adr.setType(Address::Home);
00890 
00891         addressee.insertAddress(adr);
00892 
00893         adr.setPostOfficeBox(sNamedProp(tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX));
00894         adr.setStreet(sNamedProp(tnefMsg,        MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET));
00895         adr.setLocality(sNamedProp(tnefMsg,      MAPI_TAG_CONTACT_BUSINESSADDRESSCITY));
00896         adr.setRegion(sNamedProp(tnefMsg,        MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE));
00897         adr.setPostalCode(sNamedProp(tnefMsg,    MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE));
00898         adr.setCountry(sNamedProp(tnefMsg,       MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY));
00899         adr.setType(Address::Work);
00900 
00901         addressee.insertAddress(adr);
00902 
00903         adr.setPostOfficeBox(stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX));
00904         adr.setStreet(stringProp(tnefMsg,        MAPI_TAG_PR_OTHER_ADDRESS_STREET));
00905         adr.setLocality(stringProp(tnefMsg,      MAPI_TAG_PR_OTHER_ADDRESS_CITY));
00906         adr.setRegion(stringProp(tnefMsg,        MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE));
00907         adr.setPostalCode(stringProp(tnefMsg,    MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE));
00908         adr.setCountry(stringProp(tnefMsg,       MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY));
00909         adr.setType(Address::Dom);
00910 
00911         addressee.insertAddress(adr);
00912 
00913         // problem: the 'other' address was stored by KOrganizer in
00914         //          a line looking like the following one:
00915         // vPart += "\nADR;TYPE=dom;TYPE=intl;TYPE=parcel;TYPE=postal;TYPE=work;TYPE=home:other_pobox;;other_str1\nother_str2;other_loc;other_region;other_pocode;other_country
00916 
00917         QString nr;
00918         nr = stringProp(tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER);
00919         addressee.insertPhoneNumber(KABC::PhoneNumber(nr,PhoneNumber::Home));
00920         nr = stringProp(tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER);
00921         addressee.insertPhoneNumber(KABC::PhoneNumber(nr,PhoneNumber::Work));
00922         nr = stringProp(tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER);
00923         addressee.insertPhoneNumber(KABC::PhoneNumber(nr,PhoneNumber::Cell));
00924         nr = stringProp(tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER);
00925         addressee.insertPhoneNumber(KABC::PhoneNumber(nr,PhoneNumber::Fax|PhoneNumber::Home));
00926         nr = stringProp(tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER);
00927         addressee.insertPhoneNumber(KABC::PhoneNumber(nr,PhoneNumber::Fax|PhoneNumber::Work));
00928 
00929         s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY)
00930                       .replace(QChar('-'), QString::null)
00931                       .replace(QChar(':'), QString::null);
00932         if( !s.isEmpty() )
00933           addressee.setBirthday(QDateTime::fromString(s));
00934 
00935       bOk = (!addressee.isEmpty());
00936 
00937       }else if( "IPM.NOTE" == msgClass ){
00938 
00939       } // else if ... and so on ...
00940     }
00941   }
00942 
00943   // compose return string
00944 
00945   QString s;
00946   vPart  = calFormat.toString(&cal);
00947   if (cardConv.addresseeToVCard(addressee, s, VCardConverter::v3_0))
00948     vPart += s;
00949 
00950   return bOk;
00951 }
00952 
00953 
00954 //-----------------------------------------------------------------------------
00955 bool KMGroupware::msTNEFToHTML( KMReaderWin* reader, QString& vPart, QString fname,
00956                                 QString& prefix, QString& postfix ) const
00957 {
00958   QByteArray tnef( kFileToBytes( fname, false ) );
00959   if( tnef.count() ) {
00960     int updateCounter = 0;
00961     if( msTNEFToVPart( tnef, vPart ) ){
00962       QByteArray theBody( vPart.utf8() );
00963       QString fname2( ObjectTreeParser::byteArrayToTempFile( reader,
00964                                                         "groupware",
00965                                                         "vPart_decoded.raw",
00966                                                         theBody ) );
00967       if( !fname2.isEmpty() )
00968         return vPartToHTML( updateCounter, vPart, fname2, prefix, postfix );
00969     }
00970   }else{
00971     KMessageBox::error(0, i18n("<qt>Unable to open file <b>%1</b>.</qt>").arg(fname));
00972   }
00973   return false;
00974 }
00975 
00976 
00977 //-----------------------------------------------------------------------------
00978 bool KMGroupware::foundGroupwareLink( const QString aUrl, QString& gwType, QString& gwAction,
00979                                       QString& gwAction2, QString& gwData )
00980 {
00981   static QString gwPrefix("groupware_");
00982   gwType    = "";
00983   gwAction  = "";
00984   gwAction2 = "";
00985   gwData    = "";
00986 
00987   int i1 = aUrl.find( gwPrefix );
00988   if( -1 < i1 ) {
00989     i1 += gwPrefix.length();
00990 
00991     int i2 = aUrl.find("_", i1);
00992     if( i1 <= i2 )
00993     {
00994       // retrieve gwType
00995       gwType = aUrl.mid( i1, i2-i1 );
00996       i1 = i2+1;
00997       i2 = aUrl.find("_", i1);
00998       if( i1 <= i2 )
00999       {
01000         // retrieve gwAction
01001         gwAction = aUrl.mid( i1, i2-i1 );
01002         i1 = i2+1;
01003         i2 = aUrl.find("#", i1);
01004         if( i1 <= i2 )
01005         {
01006           // retrieve gwAction2
01007           gwAction2 = aUrl.mid( i1, i2-i1 );
01008           i2 += 1;
01009           // retrieve gwData
01010           gwData = aUrl.mid( i2 );
01011         }
01012       }
01013     }
01014   }
01015   return !gwType.isEmpty();
01016 }
01017 
01018 
01019 bool KMGroupware::handleLink( const KURL &aUrl, KMMessage* msg )
01020 {
01021   QString gwType, gwAction, gwAction2, gwData;
01022 
01023   if( !aUrl.hasRef() || !foundGroupwareLink( aUrl.path()+"#"+aUrl.ref(), gwType,
01024                          gwAction, gwAction2, gwData ) )
01025     // No groupware link to handle here
01026     return false;
01027 
01028   if( gwType != "vCal" || gwData.isEmpty()
01029       || ( "request" != gwAction && "reply" != gwAction
01030        && "cancel" != gwAction ) ) {
01031     // Then we can't handle it. But it is a groupware link, so we return true
01032     kdDebug(5006) << "Unhandled groupware link\n";
01033     return true;
01034   }
01035 
01036   // Read the vCal
01037   QFile file( gwData );
01038   if( !file.open( IO_ReadOnly ) ) {
01039     kdDebug(5006) << "Could not open file " << gwData << endl;
01040     return true;
01041   }
01042   QTextStream ts( &file );
01043   ts.setEncoding( QTextStream::UnicodeUTF8 );
01044   QString vCal = ts.read();
01045   file.close();
01046 
01047   // Find the receiver if we can
01048   QString receiver;
01049   if( msg ) {
01050     KMIdentity ident = kmkernel->identityManager()->identityForAddress( msg->to() );
01051     if( ident != KMIdentity::null ) {
01052       receiver = ident.emailAddr();
01053     } else {
01054       QStringList addrs = KMMessage::splitEmailAddrList( msg->to() );
01055       bool ok;
01056       receiver = KInputDialog::getItem( i18n("Select Address"),
01057                     i18n("None of your identities match the receiver "
01058                          "of this message,<br> please choose which of "
01059                          "the following addresses is yours:"),
01060                     addrs, 0, FALSE, &ok, kmkernel->mainWin() );
01061       if( !ok ) return false;
01062     }
01063   }
01064 
01065   // Find the sender if we can
01066   QCString sender = KMMessage::getEmailAddr( msg->from() );
01067 
01068   if( "request" == gwAction )
01069     processVCalRequest( receiver.utf8(), vCal, gwAction2 );
01070   else if( "reply" == gwAction )
01071     processVCalReply( sender, vCal, gwAction2 );
01072   else if( "cancel" == gwAction )
01073     /* Note, we pass gwAction here, not gwAction2 */
01074     processVCalReply( sender, vCal, gwAction );
01075 
01076   return true;
01077 }
01078 
01079 
01085 bool KMGroupware::incomingResourceMessage( KMAccount* /*acct*/, KMMessage* /*msg*/ )
01086 {
01087 #if 0
01088   // TODO: Reimplement with DCOP
01089 
01090   if( !mUseGroupware)
01091     return false;
01092 
01093   QString vCalIn;
01094   if( vPartFoundAndDecoded( msg, vCalIn ) )
01095     return false;
01096 
01097   bool vCalInOK, vCalOutOK, isFree;
01098   QString vCalOut;
01099   QDateTime start, end;
01100   emit( signalResourceRequest( acct->intervals(), KMMessage::getEmailAddr( msg->to() ),
01101                    vCalIn, vCalInOK, vCalOut, vCalOutOK, isFree, start, end ) );
01102   if( !vCalInOK || !vCalOutOK )
01103     return false; // parsing or generation error somewhere
01104 
01105   // Check whether we are supposed to answer automatically at all
01106   KConfigGroup options( KMKernel::config(), "Groupware" );
01107   if( isFree && options.readBoolEntry( "AutoAccept", false ) )
01108     return false;
01109   if( !isFree && options.readBoolEntry( "AutoDeclConflict", false ) )
01110     return false;
01111 
01112   // Everything went fine so far, now attach the answer
01113   KMMessage* msgNew = 0;
01114   if( msg ){
01115     msgNew = msg->createReply( KMail::ReplyAuthor, vCalOut, false, true, TRUE );
01116     msgNew->setType( DwMime::kTypeText );
01117     msgNew->setSubtype( DwMime::kSubtypeVCal );
01118     msgNew->setHeaderField("Content-Type", "text/calendar; method=REPLY; charset=\"utf-8\"");
01119     internal_directlySendMessage( msgNew );
01120   }
01121 
01122   // And also record in the account.
01123   acct->addInterval( qMakePair( start, end ) );
01124 #endif
01125 
01126   return true;
01127 }
01128 
01129 
01130 void KMGroupware::reloadFolderTree() const
01131 {
01132   // Make the folder tree show the icons or not
01133   if( mMainWidget && mMainWidget->folderTree() )
01134     mMainWidget->folderTree()->reload();
01135 }
01136 
01137 #include "kmgroupware.moc"
KDE Logo
This file is part of the documentation for kmail Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat May 1 11:37:28 2004 by doxygen 1.2.15 written by Dimitri van Heesch, © 1997-2003