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 Wed Jul 28 23:58:01 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003