00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #ifdef HAVE_CONFIG_H
00036 #include <config.h>
00037 #endif
00038
00039 #include "kmailicalifaceimpl.h"
00040 #include "kmfolder.h"
00041 #include "kmfoldertree.h"
00042 #include "kmfolderdir.h"
00043 #include "kmgroupware.h"
00044 #include "kmfoldermgr.h"
00045 #include "kmcommands.h"
00046 #include "kmfolderindex.h"
00047 #include "kmmsgdict.h"
00048 #include "kmmsgpart.h"
00049 using KMail::AccountManager;
00050 #include "kmfolderimap.h"
00051 #include "globalsettings.h"
00052 #include "accountmanager.h"
00053 #include "kmfoldercachedimap.h"
00054 #include "kmacctcachedimap.h"
00055 #include "acljobs.h"
00056
00057 #include "scalix.h"
00058
00059 #include <mimelib/enum.h>
00060 #include <mimelib/utility.h>
00061 #include <mimelib/body.h>
00062 #include <mimelib/mimepp.h>
00063
00064 #include <qfile.h>
00065 #include <qmap.h>
00066 #include <qtextcodec.h>
00067
00068 #include <kdebug.h>
00069 #include <kiconloader.h>
00070 #include <kinputdialog.h>
00071 #include <dcopclient.h>
00072 #include <kmessagebox.h>
00073 #include <kconfig.h>
00074 #include <kurl.h>
00075 #include <ktempfile.h>
00076
00077 using namespace KMail;
00078
00079 QMap<QString, QString> *KMailICalIfaceImpl::mSubResourceUINamesMap = new QMap<QString, QString>;
00080
00081
00082 static void vPartMicroParser( const QString& str, QString& s );
00083 static void reloadFolderTree();
00084
00085
00086 static const struct {
00087 const char* contentsTypeStr;
00088 const char* mimetype;
00089 KFolderTreeItem::Type treeItemType;
00090 const char* annotation;
00091 const char* translatedName;
00092 } s_folderContentsType[] = {
00093 { "Mail", "application/x-vnd.kolab.mail", KFolderTreeItem::Other, "mail", I18N_NOOP( "Mail" ) },
00094 { "Calendar", "application/x-vnd.kolab.event", KFolderTreeItem::Calendar, "event", I18N_NOOP( "Calendar" ) },
00095 { "Contact", "application/x-vnd.kolab.contact", KFolderTreeItem::Contacts, "contact", I18N_NOOP( "Contacts" ) },
00096 { "Note", "application/x-vnd.kolab.note", KFolderTreeItem::Notes, "note", I18N_NOOP( "Notes" ) },
00097 { "Task", "application/x-vnd.kolab.task", KFolderTreeItem::Tasks, "task", I18N_NOOP( "Tasks" ) },
00098 { "Journal", "application/x-vnd.kolab.journal", KFolderTreeItem::Journals, "journal", I18N_NOOP( "Journal" ) }
00099 };
00100
00101 static QString folderContentsType( KMail::FolderContentsType type )
00102 {
00103 return s_folderContentsType[type].contentsTypeStr;
00104 }
00105
00106 static QString folderKolabMimeType( KMail::FolderContentsType type )
00107 {
00108 return s_folderContentsType[type].mimetype;
00109 }
00110
00111 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::globalStorageFormat() const {
00112 return GlobalSettings::self()->theIMAPResourceStorageFormat()
00113 == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
00114 }
00115
00116 static KMail::FolderContentsType folderContentsType( const QString& type )
00117 {
00118 for ( uint i = 0 ; i < sizeof s_folderContentsType / sizeof *s_folderContentsType; ++i )
00119 if ( type == s_folderContentsType[i].contentsTypeStr )
00120 return static_cast<KMail::FolderContentsType>( i );
00121 return KMail::ContentsTypeMail;
00122 }
00123
00124 static QString localizedDefaultFolderName( KMail::FolderContentsType type )
00125 {
00126 return i18n( s_folderContentsType[type].translatedName );
00127 }
00128
00129 const char* KMailICalIfaceImpl::annotationForContentsType( KMail::FolderContentsType type )
00130 {
00131 return s_folderContentsType[type].annotation;
00132 }
00133
00134 ExtraFolder::ExtraFolder( KMFolder* f )
00135 : folder( f )
00136 {
00137 folder->open("kmailicaliface::extrafolder");
00138 }
00139
00140 ExtraFolder::~ExtraFolder()
00141 {
00142 if ( folder )
00143 folder->close("kmailicaliface::extrafolder");
00144 }
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 KMailICalIfaceImpl::KMailICalIfaceImpl()
00158 : DCOPObject( "KMailICalIface" ), QObject( 0, "KMailICalIfaceImpl" ),
00159 mContacts( 0 ), mCalendar( 0 ), mNotes( 0 ), mTasks( 0 ), mJournals( 0 ),
00160 mFolderLanguage( 0 ), mFolderParentDir( 0 ), mFolderType( KMFolderTypeUnknown ),
00161 mUseResourceIMAP( false ), mResourceQuiet( false ), mHideFolders( true )
00162 {
00163
00164 connect( kmkernel, SIGNAL( configChanged() ), this, SLOT( readConfig() ) );
00165 connect( kmkernel, SIGNAL( folderRemoved( KMFolder* ) ),
00166 this, SLOT( slotFolderRemoved( KMFolder* ) ) );
00167
00168 mExtraFolders.setAutoDelete( true );
00169 mAccumulators.setAutoDelete( true );
00170 }
00171
00172
00173
00174
00175
00176
00177
00178 static DwBodyPart* findBodyPartByMimeType( const KMMessage& msg, const char* sType, const char* sSubtype, bool startsWith = false )
00179 {
00180
00181
00182 DwBodyPart* part = msg.getFirstDwBodyPart();
00183 while( part ){
00184
00185
00186 if ( part->hasHeaders() ) {
00187 DwMediaType& contentType = part->Headers().ContentType();
00188 if ( startsWith ) {
00189 if ( contentType.TypeStr() == sType
00190 && QString( contentType.SubtypeStr().c_str() ).startsWith( sSubtype ) )
00191 return part;
00192 }
00193 else
00194 if ( contentType.TypeStr() == sType
00195 && contentType.SubtypeStr() == sSubtype )
00196 return part;
00197 }
00198 part = part->Next();
00199 }
00200 return 0;
00201 }
00202
00203
00204 static DwBodyPart* findBodyPart( const KMMessage& msg, const QString& attachmentName )
00205 {
00206
00207
00208 for ( DwBodyPart* part = msg.getFirstDwBodyPart(); part; part = part->Next() ) {
00209
00210 if ( part->hasHeaders()
00211 && attachmentName == part->Headers().ContentDisposition().Filename().c_str() )
00212 return part;
00213 if ( part->hasHeaders() && attachmentName == part->Headers().ContentType().Name().c_str() )
00214 return part;
00215 }
00216 return 0;
00217 }
00218
00219 #if 0
00220 static void debugBodyParts( const char* foo, const KMMessage& msg )
00221 {
00222 kdDebug(5006) << "--debugBodyParts " << foo << "--" << endl;
00223 for ( DwBodyPart* part = msg.getFirstDwBodyPart(); part; part = part->Next() ) {
00224 if ( part->hasHeaders() ) {
00225 kdDebug(5006) << " bodypart: " << part << endl;
00226 kdDebug(5006) << " " << part->Headers().AsString().c_str() << endl;
00227 }
00228 else
00229 kdDebug(5006) << " part " << part << " has no headers" << endl;
00230 }
00231 }
00232 #else
00233 inline static void debugBodyParts( const char*, const KMMessage& ) {}
00234 #endif
00235
00236
00237
00238
00239
00240
00241 bool KMailICalIfaceImpl::updateAttachment( KMMessage& msg,
00242 const QString& attachmentURL,
00243 const QString& attachmentName,
00244 const QString& attachmentMimetype,
00245 bool lookupByName )
00246 {
00247 kdDebug(5006) << "KMailICalIfaceImpl::updateAttachment( " << attachmentURL << " )" << endl;
00248
00249 bool bOK = false;
00250
00251 KURL url( attachmentURL );
00252 if ( url.isValid() && url.isLocalFile() ) {
00253 const QString fileName( url.path() );
00254 QFile file( fileName );
00255 if( file.open( IO_ReadOnly ) ) {
00256 QByteArray rawData = file.readAll();
00257 file.close();
00258
00259
00260 KMMessagePart msgPart;
00261 msgPart.setName( attachmentName );
00262
00263 const int iSlash = attachmentMimetype.find('/');
00264 const QCString sType = attachmentMimetype.left( iSlash ).latin1();
00265 const QCString sSubtype = attachmentMimetype.mid( iSlash+1 ).latin1();
00266 msgPart.setTypeStr( sType );
00267 msgPart.setSubtypeStr( sSubtype );
00268 QCString ctd("attachment;\n filename=\"");
00269 ctd.append( attachmentName.latin1() );
00270 ctd.append("\"");
00271 msgPart.setContentDisposition( ctd );
00272 QValueList<int> dummy;
00273 msgPart.setBodyAndGuessCte( rawData, dummy );
00274 msgPart.setPartSpecifier( fileName );
00275
00276 DwBodyPart* newPart = msg.createDWBodyPart( &msgPart );
00277
00278
00279
00280 newPart->Headers().ContentDisposition().Parse();
00281
00282 DwBodyPart* part = lookupByName ? findBodyPart( msg, attachmentName )
00283 : findBodyPartByMimeType( msg, sType, sSubtype );
00284 if ( part ) {
00285
00286
00287 newPart->SetNext( part->Next() );
00288
00289
00290 *part = *newPart;
00291 delete newPart;
00292 msg.setNeedsAssembly();
00293 kdDebug(5006) << "Attachment " << attachmentName << " updated." << endl;
00294 } else {
00295 msg.addDwBodyPart( newPart );
00296 kdDebug(5006) << "Attachment " << attachmentName << " added." << endl;
00297 }
00298 bOK = true;
00299 }else{
00300 kdDebug(5006) << "Attachment " << attachmentURL << " can not be read." << endl;
00301 }
00302 }else{
00303 kdDebug(5006) << "Attachment " << attachmentURL << " not a local file." << endl;
00304 }
00305
00306 return bOK;
00307 }
00308
00309
00310 bool KMailICalIfaceImpl::kolabXMLFoundAndDecoded( const KMMessage& msg, const QString& mimetype, QString& s )
00311 {
00312 const int iSlash = mimetype.find('/');
00313 const QCString sType = mimetype.left( iSlash ).latin1();
00314 const QCString sSubtype = mimetype.mid( iSlash+1 ).latin1();
00315 DwBodyPart* part = findBodyPartByMimeType( msg, sType, sSubtype, true );
00316 if ( part ) {
00317 KMMessagePart msgPart;
00318 KMMessage::bodyPart(part, &msgPart);
00319 s = msgPart.bodyToUnicode( QTextCodec::codecForName( "utf8" ) );
00320 return true;
00321 }
00322 return false;
00323 }
00324
00325
00326
00327
00328
00329
00330
00331 bool KMailICalIfaceImpl::deleteAttachment( KMMessage& msg,
00332 const QString& attachmentName )
00333 {
00334 kdDebug(5006) << "KMailICalIfaceImpl::deleteAttachment( " << attachmentName << " )" << endl;
00335
00336 bool bOK = false;
00337
00338
00339
00340 DwBodyPart* part = findBodyPart( msg, attachmentName );
00341 if ( part ) {
00342 msg.getTopLevelPart()->Body().RemoveBodyPart( part );
00343 delete part;
00344 msg.setNeedsAssembly();
00345 kdDebug(5006) << "Attachment deleted." << endl;
00346 bOK = true;
00347 }
00348
00349 if( !bOK ){
00350 kdDebug(5006) << "Attachment " << attachmentName << " not found." << endl;
00351 }
00352
00353 return bOK;
00354 }
00355
00356 static void setIcalVcardContentTypeHeader( KMMessage *msg, KMail::FolderContentsType t, KMFolder *folder )
00357 {
00358 KMAcctCachedImap::GroupwareType groupwareType = KMAcctCachedImap::GroupwareKolab;
00359
00360 KMFolderCachedImap *imapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
00361 if ( imapFolder )
00362 groupwareType = imapFolder->account()->groupwareType();
00363
00364 msg->setType( DwMime::kTypeText );
00365 if ( t == KMail::ContentsTypeCalendar || t == KMail::ContentsTypeTask
00366 || t == KMail::ContentsTypeJournal ) {
00367 msg->setSubtype( DwMime::kSubtypeVCal );
00368
00369 if ( groupwareType == KMAcctCachedImap::GroupwareKolab )
00370 msg->setHeaderField("Content-Type",
00371 "text/calendar; method=REQUEST; charset=\"utf-8\"");
00372 else if ( groupwareType == KMAcctCachedImap::GroupwareScalix )
00373 msg->setHeaderField("Content-Type",
00374 "text/calendar; method=PUBLISH; charset=\"UTF-8\"");
00375
00376 } else if ( t == KMail::ContentsTypeContact ) {
00377 msg->setSubtype( DwMime::kSubtypeXVCard );
00378 if ( groupwareType == KMAcctCachedImap::GroupwareKolab )
00379 msg->setHeaderField( "Content-Type", "Text/X-VCard; charset=\"utf-8\"" );
00380 else if ( groupwareType == KMAcctCachedImap::GroupwareScalix )
00381 msg->setHeaderField( "Content-Type", "application/scalix-properties; charset=\"UTF-8\"" );
00382 } else {
00383 kdWarning(5006) << k_funcinfo << "Attempt to write non-groupware contents to folder" << endl;
00384 }
00385 }
00386
00387 static void setXMLContentTypeHeader( KMMessage *msg, const QString plainTextBody )
00388 {
00389
00390
00391
00392 KMMessagePart firstPart;
00393 firstPart.setType( DwMime::kTypeText );
00394 firstPart.setSubtype( DwMime::kSubtypePlain );
00395 msg->removeHeaderField( "Content-Type" );
00396 msg->setType( DwMime::kTypeMultipart );
00397 msg->setSubtype( DwMime::kSubtypeMixed );
00398 msg->headers().ContentType().CreateBoundary( 0 );
00399 msg->headers().ContentType().Assemble();
00400 firstPart.setBodyFromUnicode( plainTextBody );
00401 msg->addBodyPart( &firstPart );
00402 }
00403
00404
00405 Q_UINT32 KMailICalIfaceImpl::addIncidenceKolab( KMFolder& folder,
00406 const QString& subject,
00407 const QString& plainTextBody,
00408 const QMap<QCString, QString>& customHeaders,
00409 const QStringList& attachmentURLs,
00410 const QStringList& attachmentNames,
00411 const QStringList& attachmentMimetypes )
00412 {
00413 kdDebug(5006) << "KMailICalIfaceImpl::addIncidenceKolab( " << attachmentNames << " )" << endl;
00414
00415 Q_UINT32 sernum = 0;
00416 bool bAttachOK = true;
00417
00418
00419 KMMessage* msg = new KMMessage();
00420 msg->initHeader();
00421 msg->setSubject( subject );
00422 msg->setAutomaticFields( true );
00423
00424 QMap<QCString, QString>::ConstIterator ith = customHeaders.begin();
00425 const QMap<QCString, QString>::ConstIterator ithEnd = customHeaders.end();
00426 for ( ; ith != ithEnd ; ++ith ) {
00427 msg->setHeaderField( ith.key(), ith.data() );
00428 }
00429
00430
00431 if ( storageFormat( &folder ) == StorageXML ) {
00432 setXMLContentTypeHeader( msg, plainTextBody );
00433 } else if ( storageFormat( &folder ) == StorageIcalVcard ) {
00434 const KMail::FolderContentsType t = folder.storage()->contentsType();
00435 setIcalVcardContentTypeHeader( msg, t, &folder );
00436 msg->setBodyEncoded( plainTextBody.utf8() );
00437 } else {
00438 kdWarning(5006) << k_funcinfo << "Attempt to write to folder with unknown storage type" << endl;
00439 }
00440
00441 Q_ASSERT( attachmentMimetypes.count() == attachmentURLs.count() );
00442 Q_ASSERT( attachmentNames.count() == attachmentURLs.count() );
00443
00444 QStringList::ConstIterator itmime = attachmentMimetypes.begin();
00445 QStringList::ConstIterator iturl = attachmentURLs.begin();
00446 for( QStringList::ConstIterator itname = attachmentNames.begin();
00447 itname != attachmentNames.end()
00448 && itmime != attachmentMimetypes.end()
00449 && iturl != attachmentURLs.end();
00450 ++itname, ++iturl, ++itmime ){
00451 bool byname = !(*itmime).startsWith( "application/x-vnd.kolab." );
00452 if( !updateAttachment( *msg, *iturl, *itname, *itmime, byname ) ){
00453 kdWarning(5006) << "Attachment error, can not add Incidence." << endl;
00454 bAttachOK = false;
00455 break;
00456 }
00457 }
00458
00459 if( bAttachOK ){
00460
00461 msg->cleanupHeader();
00462
00463 msg->touch();
00464 if ( folder.addMsg( msg ) == 0 )
00465
00466 sernum = msg->getMsgSerNum();
00467 kdDebug(5006) << "addIncidenceKolab(): Message done and saved. Sernum: "
00468 << sernum << endl;
00469
00470
00471 addFolderChange( &folder, Contents );
00472 syncFolder( &folder );
00473 } else
00474 kdError(5006) << "addIncidenceKolab(): Message *NOT* saved!\n";
00475
00476 return sernum;
00477 }
00478
00479 bool KMailICalIfaceImpl::deleteIncidenceKolab( const QString& resource,
00480 Q_UINT32 sernum )
00481 {
00482
00483 if( !mUseResourceIMAP )
00484 return false;
00485
00486 kdDebug(5006) << "KMailICalIfaceImpl::deleteIncidenceKolab( "
00487 << resource << ", " << sernum << ")\n";
00488
00489
00490 KMFolder* f = findResourceFolder( resource );
00491 if( !f ) {
00492 kdError(5006) << "deleteIncidenceKolab(" << resource << ") : Not an IMAP resource folder" << endl;
00493 return false;
00494 }
00495
00496 bool rc = false;
00497
00498 KMMessage* msg = findMessageBySerNum( sernum, f );
00499 if( msg ) {
00500
00501 deleteMsg( msg );
00502 syncFolder( f );
00503 rc = true;
00504 } else {
00505 kdDebug(5006) << "Message not found, cannot remove serNum " << sernum << endl;
00506 }
00507 return rc;
00508 }
00509
00510
00511 int KMailICalIfaceImpl::incidencesKolabCount( const QString& mimetype,
00512 const QString& resource )
00513 {
00514 Q_UNUSED( mimetype );
00515
00516 if( !mUseResourceIMAP )
00517 return 0;
00518
00519 KMFolder* f = findResourceFolder( resource );
00520 if( !f ) {
00521 kdError(5006) << "incidencesKolab(" << resource << ") : Not an IMAP resource folder" << endl;
00522 return 0;
00523 }
00524
00525 f->open("kolabcount");
00526 int n = f->count();
00527 f->close("kolabcount");
00528 kdDebug(5006) << "KMailICalIfaceImpl::incidencesKolabCount( "
00529 << resource << " ) returned " << n << endl;
00530 return n;
00531 }
00532
00533 QMap<Q_UINT32, QString> KMailICalIfaceImpl::incidencesKolab( const QString& mimetype,
00534 const QString& resource,
00535 int startIndex,
00536 int nbMessages )
00537 {
00541
00542 QMap<Q_UINT32, QString> aMap;
00543 if( !mUseResourceIMAP )
00544 return aMap;
00545
00546 KMFolder* f = findResourceFolder( resource );
00547 if( !f ) {
00548 kdError(5006) << "incidencesKolab(" << resource << ") : Not an IMAP resource folder" << endl;
00549 return aMap;
00550 }
00551
00552 f->open( "incidences" );
00553
00554 if ( GlobalSettings::self()->mailLossDebug() ) {
00555 kdDebug(5006) << k_funcinfo << "Getting incidences (" << mimetype << ") for folder " << f->label()
00556 << ", starting with index " << startIndex << ", " << nbMessages << " messages." << endl;
00557 kdDebug(5006) << "The folder has " << f->count() << " messages." << endl;
00558 }
00559
00560 int stopIndex = nbMessages == -1 ? f->count() :
00561 QMIN( f->count(), startIndex + nbMessages );
00562
00563 for(int i = startIndex; i < stopIndex; ++i) {
00564 #if 0
00565 bool unget = !f->isMessage(i);
00566 KMMessage* msg = f->getMsg( i );
00567 #else // faster
00568 KMMessage* msg = f->storage()->readTemporaryMsg(i);
00569 #endif
00570 if ( msg ) {
00571 const int iSlash = mimetype.find('/');
00572 const QCString sType = mimetype.left( iSlash ).latin1();
00573 const QCString sSubtype = mimetype.mid( iSlash+1 ).latin1();
00574 if ( sType.isEmpty() || sSubtype.isEmpty() ) {
00575 kdError(5006) << mimetype << " not an type/subtype combination" << endl;
00576 } else {
00577 DwBodyPart* dwPart = findBodyPartByMimeType( *msg, sType, sSubtype );
00578 if ( dwPart ) {
00579 KMMessagePart msgPart;
00580 KMMessage::bodyPart(dwPart, &msgPart);
00581 aMap.insert(msg->getMsgSerNum(), msgPart.bodyToUnicode( QTextCodec::codecForName( "utf8" ) ));
00582 } else {
00583
00584
00585
00586 const QCString type( msg->typeStr() );
00587 const QCString subtype( msg->subtypeStr() );
00588 if (type.lower() == sType && subtype.lower() == sSubtype ) {
00589 aMap.insert( msg->getMsgSerNum(), msg->bodyToUnicode() );
00590 }
00591
00592
00593 }
00594 }
00595 #if 0
00596 if( unget ) f->unGetMsg(i);
00597 #else
00598 delete msg;
00599 #endif
00600 } else {
00601 kdDebug(5006) << k_funcinfo << " Unable to retrieve message " << i << " for incidence!" << endl;
00602 }
00603 }
00604 f->close( "incidences" );
00605 return aMap;
00606 }
00607
00608
00609
00610
00611
00612 void KMailICalIfaceImpl::slotMessageRetrieved( KMMessage* msg )
00613 {
00614 if( !msg ) return;
00615
00616 KMFolder *parent = msg->parent();
00617 Q_ASSERT( parent );
00618 Q_UINT32 sernum = msg->getMsgSerNum();
00619
00620
00621 Accumulator *ac = mAccumulators.find( parent->location() );
00622 if( ac ) {
00623 QString s;
00624 if ( !vPartFoundAndDecoded( msg, s ) ) return;
00625 QString uid( "UID" );
00626 vPartMicroParser( s, uid );
00627 const Q_UINT32 sernum = msg->getMsgSerNum();
00628 mUIDToSerNum.insert( uid, sernum );
00629 ac->add( s );
00630 if( ac->isFull() ) {
00631
00632
00633
00634 mAccumulators.remove( ac->folder );
00635 }
00636 } else {
00637
00638
00639 slotIncidenceAdded( msg->parent(), msg->getMsgSerNum() );
00640 }
00641
00642 if ( mTheUnGetMes.contains( sernum ) ) {
00643 mTheUnGetMes.remove( sernum );
00644 int i = 0;
00645 KMFolder* folder = 0;
00646 KMMsgDict::instance()->getLocation( sernum, &folder, &i );
00647 folder->unGetMsg( i );
00648 }
00649 }
00650
00651 static int dimapAccountCount()
00652 {
00653 KMail::AccountManager *mgr = kmkernel->acctMgr();
00654 KMAccount *account = mgr->first();
00655 int count = 0;
00656 while ( account ) {
00657 if ( dynamic_cast<KMAcctCachedImap*>( account ) )
00658 ++count;
00659 account = mgr->next();
00660 }
00661 return count;
00662 }
00663
00664 int KMailICalIfaceImpl::dimapAccounts()
00665 {
00666 return dimapAccountCount();
00667 }
00668
00669 static QString subresourceLabelForPresentation( const KMFolder * folder )
00670 {
00671 if( KMailICalIfaceImpl::getResourceMap()->contains( folder->location() ) ) {
00672 return folder->label();
00673 }
00674
00675 QString label = folder->prettyURL();
00676 QStringList parts = QStringList::split( QString::fromLatin1("/"), label );
00677
00678
00679
00680
00681 if ( parts[1] == QString::fromLatin1("user") ) {
00682 QStringList remainder(parts);
00683 remainder.pop_front();
00684 remainder.pop_front();
00685 remainder.pop_front();
00686 label = i18n("%1's %2")
00687 .arg( parts[2] )
00688 .arg( remainder.join( QString::fromLatin1("/") ) );
00689 }
00690
00691
00692 const KMFolder *parent = folder;
00693 while ( parent->parent() && parent->parent()->owner() ) {
00694 parent = parent->parent()->owner();
00695 if ( parent->isSystemFolder() ) {
00696 QStringList remainder(parts);
00697 remainder.pop_front();
00698 remainder.pop_front();
00699 if ( dimapAccountCount() > 1 ) {
00700
00701 if( folder->storage() && static_cast<const KMFolderCachedImap*>( folder->storage() )->account() ) {
00702 label = i18n( "My %1 (%2)")
00703 .arg( remainder.join( QString::fromLatin1("/") ),
00704 static_cast<const KMFolderCachedImap*>( folder->storage() )->account()->name() );
00705 } else {
00706 label = i18n("My %1")
00707 .arg( remainder.join( QString::fromLatin1("/") ) );
00708 }
00709 } else {
00710 label = i18n("My %1")
00711 .arg( remainder.join( QString::fromLatin1("/") ) );
00712 }
00713 break;
00714 }
00715 }
00716 return label;
00717 }
00718
00719
00720 QValueList<KMailICalIfaceImpl::SubResource> KMailICalIfaceImpl::subresourcesKolab( const QString& contentsType )
00721 {
00722 QValueList<SubResource> subResources;
00723
00724
00725 KMFolder* f = folderFromType( contentsType, QString::null );
00726 if ( f ) {
00727 subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
00728 f->isWritable(), folderIsAlarmRelevant( f ) ) );
00729 kdDebug(5006) << "Adding(1) folder " << f->location() << " " <<
00730 ( !f->isWritable() ? "readonly" : "" ) << endl;
00731 }
00732
00733
00734 const KMail::FolderContentsType t = folderContentsType( contentsType );
00735 QDictIterator<ExtraFolder> it( mExtraFolders );
00736 for ( ; it.current(); ++it ){
00737 f = it.current()->folder;
00738 if ( f && f->storage()->contentsType() == t ) {
00739 subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
00740 f->isWritable(), folderIsAlarmRelevant( f ) ) );
00741 kdDebug(5006) << "Adding(2) folder " << f->location() << " " <<
00742 ( !f->isWritable() ? "readonly" : "" ) << endl;
00743 }
00744 }
00745
00746 if ( subResources.isEmpty() )
00747 kdDebug(5006) << "subresourcesKolab: No folder found for " << contentsType << endl;
00748 return subResources;
00749 }
00750
00751 bool KMailICalIfaceImpl::triggerSync( const QString& contentsType )
00752 {
00753 kdDebug(5006) << k_funcinfo << endl;
00754 QValueList<KMailICalIfaceImpl::SubResource> folderList = subresourcesKolab( contentsType );
00755 for ( QValueList<KMailICalIfaceImpl::SubResource>::const_iterator it( folderList.begin() ),
00756 end( folderList.end() );
00757 it != end ; ++it ) {
00758 KMFolder * const f = findResourceFolder( (*it).location );
00759 if ( !f ) continue;
00760 if ( f->folderType() == KMFolderTypeImap || f->folderType() == KMFolderTypeCachedImap ) {
00761 if ( !kmkernel->askToGoOnline() ) {
00762 return false;
00763 }
00764 }
00765
00766 if ( f->folderType() == KMFolderTypeImap ) {
00767 KMFolderImap *imap = static_cast<KMFolderImap*>( f->storage() );
00768 imap->getAndCheckFolder();
00769 } else if ( f->folderType() == KMFolderTypeCachedImap ) {
00770 KMFolderCachedImap* cached = static_cast<KMFolderCachedImap*>( f->storage() );
00771 if ( cached->account() ) {
00772 cached->account()->processNewMailInFolder( f );
00773 }
00774 }
00775 }
00776 return true;
00777 }
00778
00779
00780 bool KMailICalIfaceImpl::isWritableFolder( const QString& type,
00781 const QString& resource )
00782 {
00783 KMFolder* f = folderFromType( type, resource );
00784 if ( !f )
00785
00786 return false;
00787
00788 return f->isWritable();
00789 }
00790
00791
00792 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( const QString& resource )
00793 {
00794 StorageFormat format;
00795 KMFolder* f = findResourceFolder( resource );
00796 if ( f )
00797 format = storageFormat( f );
00798 else
00799 format = globalStorageFormat();
00800 return format;
00801 }
00802
00817 Q_UINT32 KMailICalIfaceImpl::update( const QString& resource,
00818 Q_UINT32 sernum,
00819 const QString& subject,
00820 const QString& plainTextBody,
00821 const QMap<QCString, QString>& customHeaders,
00822 const QStringList& attachmentURLs,
00823 const QStringList& attachmentMimetypes,
00824 const QStringList& attachmentNames,
00825 const QStringList& deletedAttachments )
00826 {
00827 Q_UINT32 rc = 0;
00828
00829 if( !mUseResourceIMAP )
00830 return rc;
00831
00832 Q_ASSERT( !resource.isEmpty() );
00833
00834 kdDebug(5006) << "KMailICalIfaceImpl::update( " << resource << ", " << sernum << " )\n";
00835 kdDebug(5006) << attachmentURLs << "\n";
00836 kdDebug(5006) << attachmentMimetypes << "\n";
00837 kdDebug(5006) << attachmentNames << "\n";
00838 kdDebug(5006) << subject << "\n";
00839 kdDebug(5006) << "deleted attachments:" << deletedAttachments << "\n";
00840
00841
00842 KMFolder* f = findResourceFolder( resource );
00843 if( !f ) {
00844 kdError(5006) << "update(" << resource << ") : Not an IMAP resource folder" << endl;
00845 return rc;
00846 }
00847
00848 f->open( "ifaceupdate" );
00849
00850 bool checkSubject = true;
00851
00852 if ( customHeaders.contains( "X-KDE-internal-uidChanged" ) ) {
00853
00854 checkSubject = false;
00855 }
00856
00857 KMMessage* msg = 0;
00858 if ( sernum != 0 ) {
00859 if ( storageFormat( f ) == StorageXML && checkSubject ) {
00860 msg = findMessageBySerNum( sernum, f, subject );
00861 } else {
00862 msg = findMessageBySerNum( sernum, f );
00863 }
00864 if ( !msg ) return 0;
00865
00866 KMMessage* newMsg = new KMMessage( *msg );
00867 newMsg->setSubject( subject );
00868 QMap<QCString, QString>::ConstIterator ith = customHeaders.begin();
00869 const QMap<QCString, QString>::ConstIterator ithEnd = customHeaders.begin();
00870 for ( ; ith != ithEnd ; ++ith ) {
00871 if ( checkSubject == false && ith.key() != "X-KDE-internal-uidChanged" )
00872 newMsg->setHeaderField( ith.key(), ith.data() );
00873 }
00874 newMsg->setParent( 0 );
00875
00876
00877
00878 for( QStringList::ConstIterator it = deletedAttachments.begin();
00879 it != deletedAttachments.end();
00880 ++it ){
00881 if( !deleteAttachment( *newMsg, *it ) ){
00882
00883 }
00884 }
00885
00886 const KMail::FolderContentsType t = f->storage()->contentsType();
00887 const QCString type = msg->typeStr();
00888 const QCString subtype = msg->subtypeStr();
00889 const bool messageWasIcalVcardFormat = ( type.lower() == "text" &&
00890 ( subtype.lower() == "calendar" || subtype.lower() == "x-vcard" ) );
00891
00892 if ( storageFormat( f ) == StorageIcalVcard ) {
00893
00894 if ( !messageWasIcalVcardFormat ) {
00895 setIcalVcardContentTypeHeader( newMsg, t, f );
00896 }
00897 newMsg->setBodyEncoded( plainTextBody.utf8() );
00898 } else if ( storageFormat( f ) == StorageXML ) {
00899 if ( messageWasIcalVcardFormat ) {
00900
00901
00902 setXMLContentTypeHeader( newMsg, plainTextBody );
00903 }
00904
00905
00906 QStringList::ConstIterator iturl = attachmentURLs.begin();
00907 QStringList::ConstIterator itmime = attachmentMimetypes.begin();
00908 QStringList::ConstIterator itname = attachmentNames.begin();
00909 for( ;
00910 iturl != attachmentURLs.end()
00911 && itmime != attachmentMimetypes.end()
00912 && itname != attachmentNames.end();
00913 ++iturl, ++itname, ++itmime ){
00914 bool byname = !(*itmime).startsWith( "application/x-vnd.kolab." );
00915 if( !updateAttachment( *newMsg, *iturl, *itname, *itmime, byname ) ){
00916 kdDebug(5006) << "Attachment error, can not update attachment " << *iturl << endl;
00917 break;
00918 }
00919 }
00920 }
00921
00922
00923
00924
00925 newMsg->cleanupHeader();
00926
00927
00928
00929 deleteMsg( msg );
00930
00931 if ( f->addMsg( newMsg ) == 0 ) {
00932
00933 rc = newMsg->getMsgSerNum();
00934 kdDebug(5006) << "forget about " << sernum << ", it's " << rc << " now" << endl;
00935 }
00936 addFolderChange( f, Contents );
00937 syncFolder( f );
00938 } else {
00939
00940 rc = addIncidenceKolab( *f, subject, plainTextBody, customHeaders,
00941 attachmentURLs,
00942 attachmentNames,
00943 attachmentMimetypes );
00944 }
00945
00946 f->close("ifaceupdate");
00947 return rc;
00948 }
00949
00950 KURL KMailICalIfaceImpl::getAttachment( const QString& resource,
00951 Q_UINT32 sernum,
00952 const QString& filename )
00953 {
00954
00955
00956
00957 if( !mUseResourceIMAP )
00958 return KURL();
00959
00960 kdDebug(5006) << "KMailICalIfaceImpl::getAttachment( "
00961 << resource << ", " << sernum << ", " << filename << " )\n";
00962
00963
00964 KMFolder* f = findResourceFolder( resource );
00965 if( !f ) {
00966 kdError(5006) << "getAttachment(" << resource << ") : Not an IMAP resource folder" << endl;
00967 return KURL();
00968 }
00969 if ( storageFormat( f ) != StorageXML ) {
00970 kdError(5006) << "getAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
00971 return KURL();
00972 }
00973
00974 KURL url;
00975
00976 bool bOK = false;
00977 bool quiet = mResourceQuiet;
00978 mResourceQuiet = true;
00979
00980 KMMessage* msg = findMessageBySerNum( sernum, f );
00981 if( msg ) {
00982
00983
00984 DwBodyPart* part = findBodyPart( *msg, filename );
00985 if ( part ) {
00986
00987 KMMessagePart aPart;
00988 msg->bodyPart( part, &aPart );
00989 QByteArray rawData( aPart.bodyDecodedBinary() );
00990
00991 KTempFile file;
00992 file.file()->writeBlock( rawData.data(), rawData.size() );
00993
00994 url.setPath( file.name() );
00995
00996 bOK = true;
00997 }
00998
00999 if( !bOK ){
01000 kdDebug(5006) << "Attachment " << filename << " not found." << endl;
01001 }
01002 }else{
01003 kdDebug(5006) << "Message not found." << endl;
01004 }
01005
01006 mResourceQuiet = quiet;
01007 return url;
01008 }
01009
01010 QString KMailICalIfaceImpl::attachmentMimetype( const QString & resource,
01011 Q_UINT32 sernum,
01012 const QString & filename )
01013 {
01014 if( !mUseResourceIMAP )
01015 return QString();
01016 KMFolder* f = findResourceFolder( resource );
01017 if( !f || storageFormat( f ) != StorageXML ) {
01018 kdError(5006) << "attachmentMimetype(" << resource << ") : Wrong folder" << endl;
01019 return QString();
01020 }
01021
01022 KMMessage* msg = findMessageBySerNum( sernum, f );
01023 if( msg ) {
01024
01025 DwBodyPart* part = findBodyPart( *msg, filename );
01026 if ( part ) {
01027 KMMessagePart kmPart;
01028 msg->bodyPart( part, &kmPart );
01029 return QString( kmPart.typeStr() ) + "/" + QString( kmPart.subtypeStr() );
01030 } else {
01031 kdDebug(5006) << "Attachment " << filename << " not found." << endl;
01032 }
01033 } else {
01034 kdDebug(5006) << "Message not found." << endl;
01035 }
01036
01037 return QString();
01038 }
01039
01040 QStringList KMailICalIfaceImpl::listAttachments(const QString & resource, Q_UINT32 sernum)
01041 {
01042 QStringList rv;
01043 if( !mUseResourceIMAP )
01044 return rv;
01045
01046
01047 KMFolder* f = findResourceFolder( resource );
01048 if( !f ) {
01049 kdError(5006) << "listAttachments(" << resource << ") : Not an IMAP resource folder" << endl;
01050 return rv;
01051 }
01052 if ( storageFormat( f ) != StorageXML ) {
01053 kdError(5006) << "listAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
01054 return rv;
01055 }
01056
01057 KMMessage* msg = findMessageBySerNum( sernum, f );
01058 if( msg ) {
01059 for ( DwBodyPart* part = msg->getFirstDwBodyPart(); part; part = part->Next() ) {
01060 if ( part->hasHeaders() ) {
01061 QString name;
01062 DwMediaType& contentType = part->Headers().ContentType();
01063 if ( QString( contentType.SubtypeStr().c_str() ).startsWith( "x-vnd.kolab." )
01064 || QString( contentType.SubtypeStr().c_str() ).contains( "tnef" ) )
01065 continue;
01066 if ( !part->Headers().ContentDisposition().Filename().empty() )
01067 name = part->Headers().ContentDisposition().Filename().c_str();
01068 else if ( !contentType.Name().empty() )
01069 name = contentType.Name().c_str();
01070 if ( !name.isEmpty() )
01071 rv.append( name );
01072 }
01073 }
01074 } else {
01075 kdDebug(5006) << "Message not found." << endl;
01076 }
01077
01078 return rv;
01079 }
01080
01081
01082
01083
01084
01085
01086
01087
01088 void KMailICalIfaceImpl::slotFolderRemoved( KMFolder* folder )
01089 {
01090
01091
01092 folderContentsTypeChanged( folder, KMail::ContentsTypeMail );
01093 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01094 configGroup.deleteEntry( folder->idString() + "-storageFormat" );
01095 configGroup.deleteEntry( folder->idString() + "-changes" );
01096 }
01097
01098
01099 void KMailICalIfaceImpl::slotIncidenceAdded( KMFolder* folder,
01100 Q_UINT32 sernum )
01101 {
01102 if( mResourceQuiet || !mUseResourceIMAP ) {
01103
01104 return;
01105 }
01106
01107
01108
01109 QString type = folderContentsType( folder->storage()->contentsType() );
01110 if( type.isEmpty() ) {
01111 kdError(5006) << "Not an IMAP resource folder" << endl;
01112 return;
01113 }
01114
01115 int i = 0;
01116 KMFolder* aFolder = 0;
01117 KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
01118 assert( folder == aFolder );
01119
01120 bool unget = !folder->isMessage( i );
01121 QString s;
01122 QString uid( "UID" );
01123 KMMessage *msg = folder->getMsg( i );
01124 if( !msg ) return;
01125 if( msg->isComplete() ) {
01126
01127 bool ok = false;
01128 StorageFormat format = storageFormat( folder );
01129 switch( format ) {
01130 case StorageIcalVcard:
01131
01132 ok = vPartFoundAndDecoded( msg, s );
01133 if ( ok )
01134 vPartMicroParser( s, uid );
01135 break;
01136 case StorageXML:
01137
01138 if ( kolabXMLFoundAndDecoded( *msg,
01139 folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
01140 uid = msg->subject();
01141 ok = true;
01142 }
01143 break;
01144 }
01145 if ( !ok ) {
01146 if ( unget )
01147 folder->unGetMsg( i );
01148 return;
01149 }
01150 const Q_UINT32 sernum = msg->getMsgSerNum();
01151 mUIDToSerNum.insert( uid, sernum );
01152
01153
01154 if ( mInTransit.contains( uid ) ) {
01155 mInTransit.remove( uid );
01156 }
01157 incidenceAdded( type, folder->location(), sernum, format, s );
01158 } else {
01159
01160
01161 if ( unget ) mTheUnGetMes.insert( msg->getMsgSerNum(), true );
01162 FolderJob *job = msg->parent()->createJob( msg );
01163 connect( job, SIGNAL( messageRetrieved( KMMessage* ) ),
01164 this, SLOT( slotMessageRetrieved( KMMessage* ) ) );
01165 job->start();
01166 return;
01167 }
01168 if( unget ) folder->unGetMsg(i);
01169 }
01170
01171
01172 void KMailICalIfaceImpl::slotIncidenceDeleted( KMFolder* folder,
01173 Q_UINT32 sernum )
01174 {
01175 if( mResourceQuiet || !mUseResourceIMAP ) {
01176
01177 return;
01178 }
01179
01180
01181 QString type = folderContentsType( folder->storage()->contentsType() );
01182
01183 if( !type.isEmpty() ) {
01184
01185 int i = 0;
01186 KMFolder* aFolder = 0;
01187 KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
01188 assert( folder == aFolder );
01189
01190
01191 bool unget = !folder->isMessage( i );
01192 QString s;
01193 bool ok = false;
01194 KMMessage* msg = folder->getMsg( i );
01195 QString uid( "UID" );
01196 switch( storageFormat( folder ) ) {
01197 case StorageIcalVcard:
01198 if( vPartFoundAndDecoded( msg, s ) ) {
01199 vPartMicroParser( s, uid );
01200 ok = true;
01201 }
01202 break;
01203 case StorageXML:
01204 if ( kolabXMLFoundAndDecoded( *msg, folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
01205 uid = msg->subject();
01206 ok = true;
01207 }
01208 break;
01209 }
01210 if ( ok ) {
01211 kdDebug(5006) << "Emitting DCOP signal incidenceDeleted( "
01212 << type << ", " << folder->location() << ", " << uid
01213 << " )" << endl;
01214 incidenceDeleted( type, folder->location(), uid, sernum );
01215 }
01216 if( unget ) folder->unGetMsg(i);
01217 } else
01218 kdError(5006) << "Not a groupware folder" << endl;
01219 }
01220
01221
01222 void KMailICalIfaceImpl::slotRefresh( const QString& type )
01223 {
01224 if( mUseResourceIMAP ) {
01225 signalRefresh( type, QString::null );
01226 kdDebug(5006) << "Emitting DCOP signal signalRefresh( " << type << " )" << endl;
01227 }
01228 }
01229
01230
01231 void KMailICalIfaceImpl::slotRefreshFolder( KMFolder* folder)
01232 {
01233
01234
01235
01236 if( mUseResourceIMAP && folder ) {
01237 if( folder == mCalendar || folder == mContacts
01238 || folder == mNotes || folder == mTasks
01239 || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01240
01241 KMail::FolderContentsType ct = folder->storage()->contentsType();
01242 slotRefresh( s_folderContentsType[ct].contentsTypeStr );
01243 }
01244 }
01245 }
01246
01247
01248
01249
01250
01251 KMFolder* KMailICalIfaceImpl::folderFromType( const QString& type,
01252 const QString& folder )
01253 {
01254 if( mUseResourceIMAP ) {
01255 KMFolder* f = 0;
01256 if ( !folder.isEmpty() ) {
01257 f = extraFolder( type, folder );
01258 if ( f )
01259 return f;
01260 }
01261
01262 if( type == "Calendar" ) f = mCalendar;
01263 else if( type == "Contact" ) f = mContacts;
01264 else if( type == "Note" ) f = mNotes;
01265 else if( type == "Task" || type == "Todo" ) f = mTasks;
01266 else if( type == "Journal" ) f = mJournals;
01267
01268 if ( f && ( folder.isEmpty() || folder == f->location() ) )
01269 return f;
01270
01271 kdError(5006) << "No folder ( " << type << ", " << folder << " )\n";
01272 }
01273
01274 return 0;
01275 }
01276
01277
01278
01279
01280 bool KMailICalIfaceImpl::isResourceFolder( KMFolder* folder ) const
01281 {
01282 return mUseResourceIMAP && folder &&
01283 ( isStandardResourceFolder( folder ) || mExtraFolders.find( folder->location() )!=0 );
01284 }
01285
01286 bool KMailICalIfaceImpl::isStandardResourceFolder( KMFolder* folder ) const
01287 {
01288 return ( folder == mCalendar || folder == mTasks || folder == mJournals ||
01289 folder == mNotes || folder == mContacts );
01290 }
01291
01292 bool KMailICalIfaceImpl::hideResourceFolder( KMFolder* folder ) const
01293 {
01294 return mHideFolders && isResourceFolder( folder );
01295 }
01296
01297 bool KMailICalIfaceImpl::hideResourceAccountRoot( KMFolder* folder ) const
01298 {
01299 KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
01300 bool hide = dimapFolder && mHideFolders
01301 && (int)dimapFolder->account()->id() == GlobalSettings::self()->theIMAPResourceAccount()
01302 && GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount();
01303 return hide;
01304
01305 }
01306
01307 KFolderTreeItem::Type KMailICalIfaceImpl::folderType( KMFolder* folder ) const
01308 {
01309 if( mUseResourceIMAP && folder ) {
01310 if( folder == mCalendar || folder == mContacts
01311 || folder == mNotes || folder == mTasks
01312 || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01313 KMail::FolderContentsType ct = folder->storage()->contentsType();
01314 return s_folderContentsType[ct].treeItemType;
01315 }
01316 }
01317
01318 return KFolderTreeItem::Other;
01319 }
01320
01321
01322
01323 static QMap<KFolderTreeItem::Type,QString> folderNames[4];
01324 QString KMailICalIfaceImpl::folderName( KFolderTreeItem::Type type, int language ) const
01325 {
01326
01327 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
01328 language = 0;
01329
01330 static bool folderNamesSet = false;
01331 if( !folderNamesSet ) {
01332 folderNamesSet = true;
01333
01334
01335
01336
01337 folderNames[0][KFolderTreeItem::Calendar] = QString::fromLatin1("Calendar");
01338 folderNames[0][KFolderTreeItem::Tasks] = QString::fromLatin1("Tasks");
01339 folderNames[0][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01340 folderNames[0][KFolderTreeItem::Contacts] = QString::fromLatin1("Contacts");
01341 folderNames[0][KFolderTreeItem::Notes] = QString::fromLatin1("Notes");
01342
01343
01344 folderNames[1][KFolderTreeItem::Calendar] = QString::fromLatin1("Kalender");
01345 folderNames[1][KFolderTreeItem::Tasks] = QString::fromLatin1("Aufgaben");
01346 folderNames[1][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01347 folderNames[1][KFolderTreeItem::Contacts] = QString::fromLatin1("Kontakte");
01348 folderNames[1][KFolderTreeItem::Notes] = QString::fromLatin1("Notizen");
01349
01350
01351 folderNames[2][KFolderTreeItem::Calendar] = QString::fromLatin1("Calendrier");
01352
01353 folderNames[2][KFolderTreeItem::Tasks] = QString::fromLatin1("T\342ches");
01354 folderNames[2][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01355 folderNames[2][KFolderTreeItem::Contacts] = QString::fromLatin1("Contacts");
01356 folderNames[2][KFolderTreeItem::Notes] = QString::fromLatin1("Notes");
01357
01358
01359 folderNames[3][KFolderTreeItem::Calendar] = QString::fromLatin1("Agenda");
01360 folderNames[3][KFolderTreeItem::Tasks] = QString::fromLatin1("Taken");
01361 folderNames[3][KFolderTreeItem::Journals] = QString::fromLatin1("Logboek");
01362 folderNames[3][KFolderTreeItem::Contacts] = QString::fromLatin1("Contactpersonen");
01363 folderNames[3][KFolderTreeItem::Notes] = QString::fromLatin1("Notities");
01364 }
01365
01366 if( language < 0 || language > 3 ) {
01367 return folderNames[mFolderLanguage][type];
01368 }
01369 else {
01370 return folderNames[language][type];
01371 }
01372 }
01373
01374
01375
01376 KMMessage *KMailICalIfaceImpl::findMessageByUID( const QString& uid, KMFolder* folder )
01377 {
01378 if( !folder || !mUIDToSerNum.contains( uid ) ) return 0;
01379 int i;
01380 KMFolder *aFolder;
01381 KMMsgDict::instance()->getLocation( mUIDToSerNum[uid], &aFolder, &i );
01382 Q_ASSERT( aFolder == folder );
01383 return folder->getMsg( i );
01384 }
01385
01386
01387 KMMessage *KMailICalIfaceImpl::findMessageBySerNum( Q_UINT32 serNum, KMFolder* folder, const QString& subject )
01388 {
01389 if( !folder ) return 0;
01390
01391 KMMessage *message = 0;
01392 KMFolder* aFolder = 0;
01393 int index;
01394 KMMsgDict::instance()->getLocation( serNum, &aFolder, &index );
01395
01396 if( aFolder && aFolder != folder ) {
01397 kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) found it in folder " << aFolder->location() << ", expected " << folder->location() << endl;
01398 } else {
01399 if( aFolder )
01400 message = aFolder->getMsg( index );
01401 if (!message) {
01402 kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) invalid serial number\n" << endl;
01403 return 0;
01404 }
01405 }
01406
01407
01408
01409
01410
01411
01412
01413 if ( !subject.isEmpty() ) {
01414 if ( message->subject() != subject ) {
01415
01416 kdWarning(5006) << k_funcinfo << " Subject check failed!" << endl
01417 << "Got: " << message->subject() << endl
01418 << "Expected: " << subject << endl;
01419 sleep( 1 );
01420 message = aFolder->getMsg( index );
01421 if ( !message ) {
01422 kdWarning(5006) << "Second getMsg returned 0" << endl;
01423 return 0;
01424 }
01425 if ( message->subject() != subject ) {
01426 kdWarning(5006) << "Still got the wrong message: " << message->subject() << endl;
01427 KMFolderCachedImap * cimapFolder = dynamic_cast<KMFolderCachedImap *> ( aFolder->storage() );
01428 if ( cimapFolder != NULL ) {
01429 cimapFolder->markForReindexing();
01430 } else {
01431
01432 kdWarning(5006) << "Folder is not a cached IMAP folder" << endl;
01433 }
01434 if ( corruptionDialogShown ) {
01435
01436 return 0;
01437 }
01438 const QString errMsg = i18n("<qt>Kontact has detected a corruption in the folder: <br/> %1 <br/>"
01439 "Your current changes could not be saved.<br/><br/>"
01440 "It is <b>strongly</b> recommended that you restart Kontact now.<br/>"
01441 "Quit now?</qt>").arg(folder->prettyURL());
01442 corruptionDialogShown = true;
01443 if ( KMessageBox::warningYesNo( 0, errMsg, i18n("Invalid state detected") ) == KMessageBox::Yes ) {
01444 qApp->quit();
01445 } else {
01446 return 0;
01447 }
01448 } else {
01449 kdDebug(5006) << "Got the right message now, phew" << endl;
01450 }
01451 }
01452 }
01453 return message;
01454 }
01455
01456 void KMailICalIfaceImpl::deleteMsg( KMMessage *msg )
01457 {
01458 if( !msg ) return;
01459
01460
01461 KMFolder *srcFolder = msg->parent();
01462 int idx = srcFolder->find(msg);
01463 assert(idx != -1);
01464
01465 srcFolder->ignoreJobsForMessage( msg );
01466 if ( !msg->transferInProgress() ) {
01467 srcFolder->removeMsg(idx);
01468 delete msg;
01469 } else {
01470 kdDebug(5006) << k_funcinfo << "DEBUG Message cannot be deleted now because it is currently in use " << msg << endl;
01471 msg->deleteWhenUnused();
01472 }
01473 addFolderChange( srcFolder, Contents );
01474 }
01475
01476 void KMailICalIfaceImpl::folderContentsTypeChanged( KMFolder* folder,
01477 KMail::FolderContentsType contentsType )
01478 {
01479 if ( !mUseResourceIMAP )
01480 return;
01481
01482
01483
01484
01485 if ( isStandardResourceFolder( folder ) )
01486 return;
01487
01488
01489 const QString location = folder->location();
01490 ExtraFolder* ef = mExtraFolders.find( location );
01491 if ( ef && ef->folder ) {
01492
01493 subresourceDeleted(folderContentsType( folder->storage()->contentsType() ), location );
01494
01495 if ( contentsType == KMail::ContentsTypeMail ) {
01496
01497 mExtraFolders.remove( location );
01498 folder->disconnect( this );
01499 return;
01500 }
01501
01502 } else {
01503 if ( ef && !ef->folder )
01504 mExtraFolders.remove( location );
01505 if ( contentsType == KMail::ContentsTypeMail )
01506 return;
01507
01508
01509
01510 ef = new ExtraFolder( folder );
01511 mExtraFolders.insert( location, ef );
01512
01513 FolderInfo info = readFolderInfo( folder );
01514 mFolderInfoMap.insert( folder, info );
01515
01516
01517
01518
01519
01520
01521 if ( folder->folderType() == KMFolderTypeCachedImap ) {
01522 QString annotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
01523 kdDebug(5006) << "folderContentsTypeChanged: " << folder->name() << " has annotation " << annotation << endl;
01524 if ( annotation == QString( s_folderContentsType[contentsType].annotation ) + ".default" )
01525 folder->setLabel( localizedDefaultFolderName( contentsType ) );
01526 }
01527
01528 connectFolder( folder );
01529 }
01530
01531 subresourceAdded( folderContentsType( contentsType ), location, subresourceLabelForPresentation(folder),
01532 folder->isWritable(), folderIsAlarmRelevant( folder ) );
01533 }
01534
01535 KMFolder* KMailICalIfaceImpl::extraFolder( const QString& type,
01536 const QString& folder )
01537 {
01538
01539
01540 int t = folderContentsType( type );
01541 if ( t < 1 || t > 5 )
01542 return 0;
01543
01544 ExtraFolder* ef = mExtraFolders.find( folder );
01545 if ( ef && ef->folder && ef->folder->storage()->contentsType() == t )
01546 return ef->folder;
01547
01548 return 0;
01549 }
01550
01551 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( KMFolder* folder ) const
01552 {
01553 FolderInfoMap::ConstIterator it = mFolderInfoMap.find( folder );
01554 if ( it != mFolderInfoMap.end() )
01555 return (*it).mStorageFormat;
01556 return globalStorageFormat();
01557 }
01558
01559 void KMailICalIfaceImpl::setStorageFormat( KMFolder* folder, StorageFormat format )
01560 {
01561 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01562 if ( it != mFolderInfoMap.end() ) {
01563 (*it).mStorageFormat = format;
01564 } else {
01565 FolderInfo info( format, NoChange );
01566 mFolderInfoMap.insert( folder, info );
01567 }
01568 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01569 configGroup.writeEntry( folder->idString() + "-storageFormat",
01570 format == StorageXML ? "xml" : "icalvcard" );
01571 }
01572
01573 void KMailICalIfaceImpl::addFolderChange( KMFolder* folder, FolderChanges changes )
01574 {
01575 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01576 if ( it != mFolderInfoMap.end() ) {
01577 (*it).mChanges = static_cast<FolderChanges>( (*it).mChanges | changes );
01578 } else {
01579 kdDebug(5006) << "addFolderChange: nothing known about folder " << folder->location() << endl;
01580 }
01581 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01582 configGroup.writeEntry( folder->idString() + "-changes", (*it).mChanges );
01583 }
01584
01585 KMailICalIfaceImpl::FolderInfo KMailICalIfaceImpl::readFolderInfo( const KMFolder * const folder ) const
01586 {
01587 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01588 QString str = configGroup.readEntry( folder->idString() + "-storageFormat", "unset" );
01589 FolderInfo info;
01590 if ( str == "unset" ) {
01591 info.mStorageFormat = globalStorageFormat();
01592 configGroup.writeEntry( folder->idString() + "-storageFormat",
01593 info.mStorageFormat == StorageXML ? "xml" : "icalvcard" );
01594 } else {
01595 info.mStorageFormat = ( str == "xml" ) ? StorageXML : StorageIcalVcard;
01596 }
01597 info.mChanges = (FolderChanges) configGroup.readNumEntry( folder->idString() + "-changes" );
01598 return info;
01599 }
01600
01601
01602 void KMailICalIfaceImpl::folderSynced( KMFolder* folder, const KURL& folderURL )
01603 {
01604 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01605 if ( it != mFolderInfoMap.end() && (*it).mChanges ) {
01606 handleFolderSynced( folder, folderURL, (*it).mChanges );
01607 (*it).mChanges = NoChange;
01608 }
01609 }
01610
01611 void KMailICalIfaceImpl::handleFolderSynced( KMFolder* folder,
01612 const KURL& folderURL,
01613 int _changes )
01614 {
01615
01616
01617
01618
01619 if ( ( _changes & KMailICalIface::Contents ) ||
01620 ( _changes & KMailICalIface::ACL ) ) {
01621 if ( storageFormat( folder ) == StorageXML && folder->storage()->contentsType() == KMail::ContentsTypeCalendar )
01622 triggerKolabFreeBusy( folderURL, true );
01623 }
01624 }
01625
01626 void KMailICalIfaceImpl::folderDeletedOnServer( const KURL& folderURL )
01627 {
01628 triggerKolabFreeBusy( folderURL, false );
01629 }
01630
01631 void KMailICalIfaceImpl::triggerKolabFreeBusy( const KURL& folderURL, bool report )
01632 {
01633
01634
01635
01636 KURL httpURL( folderURL );
01637
01638 httpURL.setProtocol( "https" );
01639 httpURL.setPort( 0 );
01640
01641
01642 QString path = folderURL.path( -1 );
01643 Q_ASSERT( path.startsWith( "/" ) );
01644 int secondSlash = path.find( '/', 1 );
01645 if ( secondSlash == -1 ) {
01646 kdWarning() << "KCal::ResourceKolab::fromKMailFolderSynced path is too short: " << path << endl;
01647 return;
01648 }
01649 if ( path.startsWith( "/INBOX/", false ) ) {
01650
01651 path = path.mid( secondSlash );
01652 path.prepend( folderURL.user() );
01653 } else {
01654
01655
01656 path = path.mid( secondSlash );
01657 }
01658
01659 if ( path.startsWith( "/" ) )
01660 httpURL.setPath( "/freebusy/trigger" + path + ".pfb" );
01661 else
01662 httpURL.setPath( "/freebusy/trigger/" + path + ".pfb" );
01663
01664 httpURL.setQuery( QString::null );
01665
01666 httpURL = KURL( httpURL.url(0,106), 106 );
01667 kdDebug() << "Triggering PFB update for " << folderURL << " : getting " << httpURL << endl;
01668
01669 if ( report ) {
01670 KIO::Job* job = KIO::get( httpURL, false, false );
01671 job->addMetaData( "errorPage", "false" );
01672 connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( slotFreeBusyTriggerResult( KIO::Job* ) ) );
01673 }
01674 }
01675
01676 void KMailICalIfaceImpl::slotFreeBusyTriggerResult( KIO::Job *job )
01677 {
01678 if ( job->error() ) {
01679 KURL url( job->errorText() );
01680 KMessageBox::sorry(0, i18n("Could not trigger Free/Busy information update: %1.").arg( url.prettyURL() ) );
01681 }
01682 }
01683
01684 void KMailICalIfaceImpl::slotFolderPropertiesChanged( KMFolder* folder )
01685 {
01686 if ( isResourceFolder( folder ) ) {
01687 const QString location = folder->location();
01688 const QString contentsTypeStr = folderContentsType( folder->storage()->contentsType() );
01689 subresourceDeleted( contentsTypeStr, location );
01690
01691 subresourceAdded( contentsTypeStr, location, subresourceLabelForPresentation( folder ),
01692 folder->isWritable(), folderIsAlarmRelevant( folder ) );
01693 }
01694 }
01695
01696
01697 void KMailICalIfaceImpl::slotFolderRenamed()
01698 {
01699 const KMFolder* folder = static_cast<const KMFolder *>( sender() );
01700 slotFolderPropertiesChanged( const_cast<KMFolder*>( folder ) );
01701 }
01702
01703 void KMailICalIfaceImpl::slotFolderLocationChanged( const QString &oldLocation,
01704 const QString &newLocation )
01705 {
01706 KMFolder *folder = findResourceFolder( oldLocation );
01707 ExtraFolder* ef = mExtraFolders.find( oldLocation );
01708 if ( ef ) {
01709
01710 mExtraFolders.setAutoDelete( false );
01711 mExtraFolders.remove( oldLocation );
01712 mExtraFolders.setAutoDelete( true );
01713 mExtraFolders.insert( newLocation, ef );
01714 }
01715 if ( folder )
01716 subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), oldLocation );
01717
01718 }
01719
01720 KMFolder* KMailICalIfaceImpl::findResourceFolder( const QString& resource )
01721 {
01722
01723 if( mCalendar && mCalendar->location() == resource )
01724 return mCalendar;
01725 if ( mContacts && mContacts->location() == resource )
01726 return mContacts;
01727 if ( mNotes && mNotes->location() == resource )
01728 return mNotes;
01729 if ( mTasks && mTasks->location() == resource )
01730 return mTasks;
01731 if ( mJournals && mJournals->location() == resource )
01732 return mJournals;
01733
01734
01735 ExtraFolder* ef = mExtraFolders.find( resource );
01736 if ( ef )
01737 return ef->folder;
01738
01739
01740 return 0;
01741 }
01742
01743 QString KMailICalIfaceImpl::dimapFolderAccountName( const QString &folderPath )
01744 {
01745 QString name;
01746 KMFolder *f = findResourceFolder( folderPath );
01747 if ( f ) {
01748 if ( f->storage() && static_cast<const KMFolderCachedImap*>( f->storage() )->account() ) {
01749 name = static_cast<const KMFolderCachedImap*>( f->storage() )->account()->name();
01750 }
01751 }
01752 return name;
01753 }
01754
01755 void KMailICalIfaceImpl::changeResourceUIName( const QString &folderPath, const QString &newName )
01756 {
01757 kdDebug() << "Folder path " << folderPath << endl;
01758 KMFolder *f = findResourceFolder( folderPath );
01759 if ( f ) {
01760 KMailICalIfaceImpl::getResourceMap()->insert( folderPath, newName );
01761 kmkernel->folderMgr()->renameFolder( f, newName );
01762 KConfigGroup configGroup( kmkernel->config(), "Resource UINames" );
01763 configGroup.writeEntry( folderPath, newName );
01764 }
01765 }
01766
01767
01768 static void createFolderList( QStringList &folderNames, QValueList<QGuardedPtr<KMFolder> > &folderList )
01769 {
01770 QStringList dimapFolderNames;
01771 QStringList localFolderNames;
01772 QValueList<QGuardedPtr<KMFolder> > dimapFolderList;
01773 QValueList<QGuardedPtr<KMFolder> > localFolderList;
01774 kmkernel->dimapFolderMgr()->createFolderList( &dimapFolderNames, &dimapFolderList );
01775 kmkernel->folderMgr()->createFolderList( &localFolderNames, &localFolderList );
01776 folderNames += dimapFolderNames;
01777 folderNames += localFolderNames;
01778 folderList += dimapFolderList;
01779 folderList += localFolderList;
01780 }
01781
01782
01783
01784
01785
01786 void KMailICalIfaceImpl::readConfig()
01787 {
01788 bool enabled = GlobalSettings::self()->theIMAPResourceEnabled() &&
01789 ( GlobalSettings::self()->theIMAPResourceAccount() != 0 );
01790
01791 if( !enabled ) {
01792 if( mUseResourceIMAP == true ) {
01793
01794 mUseResourceIMAP = false;
01795 cleanup();
01796 reloadFolderTree();
01797 }
01798 return;
01799 }
01800 mUseResourceIMAP = enabled;
01801
01802
01803 const bool hideFolders = GlobalSettings::self()->hideGroupwareFolders();
01804 QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01805
01806
01807 KMFolderDir* folderParentDir;
01808 KMFolderType folderType;
01809 KMFolder* folderParent = kmkernel->findFolderById( parentName );
01810 if( folderParent == 0 ) {
01811
01812
01813 kdDebug(5006) << "Groupware folder " << parentName << " not found. Groupware functionality disabled" << endl;
01814
01815 KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01816 Q_ASSERT( account );
01817 if ( account ) {
01818
01819 disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01820 this, SLOT( slotCheckDone() ) );
01821 connect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01822 this, SLOT( slotCheckDone() ) );
01823 }
01824 mUseResourceIMAP = false;
01825
01826 mCalendar = 0;
01827 mTasks = 0;
01828 mJournals = 0;
01829 mContacts = 0;
01830 mNotes = 0;
01831 return;
01832 } else {
01833 folderParentDir = folderParent->createChildFolder();
01834 folderType = folderParent->folderType();
01835 }
01836
01837 KMAcctCachedImap::GroupwareType groupwareType = dynamic_cast<KMFolderCachedImap *>( folderParent->storage() )->account()->groupwareType();
01838
01839 if ( groupwareType == KMAcctCachedImap::GroupwareKolab ) {
01840
01841
01842 bool noneFound = true;
01843 bool mustFix = false;
01844 QValueVector<StandardFolderSearchResult> results( KMail::ContentsTypeLast + 1 );
01845 for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01846 if ( i != KMail::ContentsTypeMail ) {
01847 results[i] = findStandardResourceFolder( folderParentDir, static_cast<KMail::FolderContentsType>(i) );
01848 if ( results[i].found == StandardFolderSearchResult::FoundAndStandard )
01849 noneFound = false;
01850 else if ( results[i].found == StandardFolderSearchResult::FoundByType ||
01851 results[i].found == StandardFolderSearchResult::FoundByName ) {
01852 mustFix = true;
01853 noneFound = false;
01854 } else
01855 mustFix = true;
01856 }
01857 }
01858
01859
01860 if( mUseResourceIMAP && !noneFound && !mustFix && mFolderParentDir == folderParentDir
01861 && mFolderType == folderType ) {
01862
01863 if ( hideFolders != mHideFolders ) {
01864
01865 mHideFolders = hideFolders;
01866 reloadFolderTree();
01867 }
01868 return;
01869 }
01870
01871 if( noneFound || mustFix ) {
01872 QString msg;
01873 QString parentFolderName = folderParent != 0 ? folderParent->name() : folderParentDir->name();
01874 if ( noneFound ) {
01875
01876 msg = i18n("KMail will now create the required groupware folders"
01877 " as subfolders of %1; if you do not want this, cancel"
01878 " and the IMAP resource will be disabled").arg(parentFolderName);
01879 } else {
01880
01881 QString operations = "<ul>";
01882 for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01883 if ( i != KMail::ContentsTypeMail ) {
01884 QString typeName = localizedDefaultFolderName( static_cast<KMail::FolderContentsType>( i ) );
01885 if ( results[i].found == StandardFolderSearchResult::NotFound )
01886 operations += "<li>" + i18n( "%1: no folder found. It will be created." ).arg( typeName ) + "</li>";
01887 else if ( results[i].found == StandardFolderSearchResult::FoundByType || results[i].found == StandardFolderSearchResult::FoundByName )
01888 operations += "<li>" + i18n( "%1: found folder %2. It will be set as the main groupware folder." ).
01889 arg( typeName ).arg( results[i].folder->label() ) + "</li>";
01890 }
01891 }
01892 operations += "</ul>";
01893
01894 msg = i18n("<qt>KMail found the following groupware folders in %1 and needs to perform the following operations: %2"
01895 "<br>If you do not want this, cancel"
01896 " and the IMAP resource will be disabled").arg(parentFolderName, operations);
01897
01898 }
01899
01900 if( KMessageBox::questionYesNo( 0, msg,
01901 i18n("Standard Groupware Folders"), KStdGuiItem::cont(), KStdGuiItem::cancel() ) == KMessageBox::No ) {
01902
01903 GlobalSettings::self()->setTheIMAPResourceEnabled( false );
01904 mUseResourceIMAP = false;
01905 mFolderParentDir = 0;
01906 mFolderParent = 0;
01907 reloadFolderTree();
01908 return;
01909 }
01910 }
01911
01912
01913 mUseResourceIMAP = true;
01914 mFolderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
01915 if( mFolderLanguage > 3 ) mFolderLanguage = 0;
01916 mFolderParentDir = folderParentDir;
01917 mFolderParent = folderParent;
01918 mFolderType = folderType;
01919 mHideFolders = hideFolders;
01920
01921
01922 cleanup();
01923
01924
01925 mCalendar = initFolder( KMail::ContentsTypeCalendar );
01926 mTasks = initFolder( KMail::ContentsTypeTask );
01927 mJournals = initFolder( KMail::ContentsTypeJournal );
01928 mContacts = initFolder( KMail::ContentsTypeContact );
01929 mNotes = initFolder( KMail::ContentsTypeNote );
01930
01931
01932 if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01933 static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01934 if ( mTasks->folderType() == KMFolderTypeCachedImap )
01935 static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01936 if ( mJournals->folderType() == KMFolderTypeCachedImap )
01937 static_cast<KMFolderCachedImap *>( mJournals->storage() )->updateAnnotationFolderType();
01938 if ( mContacts->folderType() == KMFolderTypeCachedImap )
01939 static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01940 if ( mNotes->folderType() == KMFolderTypeCachedImap )
01941 static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01942
01943
01944
01945
01946
01947
01948 QStringList folderNames;
01949 QValueList<QGuardedPtr<KMFolder> > folderList;
01950 createFolderList( folderNames, folderList );
01951 for( QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
01952 it != folderList.end(); ++it )
01953 {
01954 FolderStorage *storage = (*it)->storage();
01955 KMFolderCachedImap* dimapStorage = dynamic_cast<KMFolderCachedImap*>( storage );
01956 if ( storage && storage->contentsType() != 0 ) {
01957 if ( dimapStorage )
01958 dimapStorage->updateAnnotationFolderType();
01959 folderContentsTypeChanged( *it, storage->contentsType() );
01960 }
01961 }
01962
01963
01964
01965 mExtraFolders.remove( mCalendar->location() );
01966 mExtraFolders.remove( mTasks->location() );
01967 mExtraFolders.remove( mJournals->location() );
01968 mExtraFolders.remove( mContacts->location() );
01969 mExtraFolders.remove( mNotes->location() );
01970
01971 subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
01972 subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
01973 subresourceAdded( folderContentsType( KMail::ContentsTypeJournal ), mJournals->location(), mJournals->label(), true, false );
01974 subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
01975 subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
01976 } else if ( groupwareType == KMAcctCachedImap::GroupwareScalix ) {
01977
01978 mUseResourceIMAP = true;
01979 mFolderParentDir = folderParentDir;
01980 mFolderParent = folderParent;
01981 mFolderType = folderType;
01982 mHideFolders = false;
01983
01984
01985 cleanup();
01986
01987
01988 mCalendar = initScalixFolder( KMail::ContentsTypeCalendar );
01989 mTasks = initScalixFolder( KMail::ContentsTypeTask );
01990 mJournals = 0;
01991 mContacts = initScalixFolder( KMail::ContentsTypeContact );
01992 mNotes = initScalixFolder( KMail::ContentsTypeNote );
01993
01994
01995 if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01996 static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01997 if ( mTasks->folderType() == KMFolderTypeCachedImap )
01998 static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01999 if ( mContacts->folderType() == KMFolderTypeCachedImap )
02000 static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
02001 if ( mNotes->folderType() == KMFolderTypeCachedImap )
02002 static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
02003
02004
02005
02006
02007 kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
02008 kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
02009 kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
02010
02011
02012 QStringList folderNames;
02013 QValueList<QGuardedPtr<KMFolder> > folderList;
02014 kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
02015 QValueList<QGuardedPtr<KMFolder> >::iterator it;
02016 for(it = folderList.begin(); it != folderList.end(); ++it)
02017 {
02018 FolderStorage *storage = (*it)->storage();
02019
02020 if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
02021 KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
02022
02023 const QString attributes = imapFolder->folderAttributes();
02024 if ( attributes.contains( "X-FolderClass" ) ) {
02025 if ( !attributes.contains( "X-SpecialFolder" ) || (*it)->location().contains( "@" ) ) {
02026 const Scalix::FolderAttributeParser parser( attributes );
02027 if ( !parser.folderClass().isEmpty() ) {
02028 FolderContentsType type = Scalix::Utils::scalixIdToContentsType( parser.folderClass() );
02029 imapFolder->setContentsType( type );
02030 folderContentsTypeChanged( *it, type );
02031 }
02032 }
02033 }
02034 }
02035 }
02036
02037
02038
02039 mExtraFolders.remove( mCalendar->location() );
02040 mExtraFolders.remove( mTasks->location() );
02041 mExtraFolders.remove( mContacts->location() );
02042 mExtraFolders.remove( mNotes->location() );
02043
02044
02045
02046 subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
02047 subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
02048 subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
02049 subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
02050 }
02051
02052 KConfig *config = kmkernel->config();
02053 config->setGroup("Resource UINames");
02054 *KMailICalIfaceImpl::mSubResourceUINamesMap = config->entryMap( "Resource UINames" );
02055
02056 reloadFolderTree();
02057 }
02058
02059 void KMailICalIfaceImpl::slotCheckDone()
02060 {
02061 QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
02062 KMFolder* folderParent = kmkernel->findFolderById( parentName );
02063
02064 if ( folderParent )
02065 {
02066 KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
02067 if ( account )
02068 disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
02069 this, SLOT( slotCheckDone() ) );
02070 readConfig();
02071 }
02072 }
02073
02074 KMFolder* KMailICalIfaceImpl::initFolder( KMail::FolderContentsType contentsType )
02075 {
02076
02077 KMFolderType type = mFolderType;
02078 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02079
02080 KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
02081
02082
02083
02084 StandardFolderSearchResult result = findStandardResourceFolder( mFolderParentDir, contentsType );
02085
02086
02087 if ( result.folders.count() > 1 && result.found == StandardFolderSearchResult::FoundAndStandard ) {
02088 QStringList labels;
02089 for ( QValueList<KMFolder*>::ConstIterator it = result.folders.begin(); it != result.folders.end(); ++it )
02090 labels << (*it)->prettyURL();
02091 const QString selected = KInputDialog::getItem( i18n("Default folder"),
02092 i18n("There are multiple %1 default folders, please choose one:")
02093 .arg( localizedDefaultFolderName( contentsType ) ), labels );
02094 if ( !selected.isEmpty() )
02095 result.folder = result.folders[ labels.findIndex( selected ) ];
02096 }
02097
02098 KMFolder* folder = result.folder;
02099
02100 if ( !folder ) {
02101
02102 folder =
02103 mFolderParentDir->createFolder( localizedDefaultFolderName( contentsType ), false, type );
02104 if( mFolderType == KMFolderTypeImap ) {
02105 KMFolderImap* parentFolder = static_cast<KMFolderImap*>( mFolderParent->storage() );
02106 parentFolder->createFolder( localizedDefaultFolderName( contentsType ) );
02107 static_cast<KMFolderImap*>( folder->storage() )->setAccount( parentFolder->account() );
02108 }
02109
02110 setStorageFormat( folder, globalStorageFormat() );
02111 } else {
02112 FolderInfo info = readFolderInfo( folder );
02113 mFolderInfoMap.insert( folder, info );
02114
02115 }
02116
02117 if( folder->canAccess() != 0 ) {
02118 KMessageBox::sorry(0, i18n("You do not have read/write permission to your %1 folder.")
02119 .arg( folderName( itemType ) ) );
02120 return 0;
02121 }
02122 folder->storage()->setContentsType( contentsType );
02123 folder->setSystemFolder( true );
02124 folder->storage()->writeConfig();
02125 folder->open("ifacefolder");
02126 connectFolder( folder );
02127 return folder;
02128 }
02129
02130 KMFolder* KMailICalIfaceImpl::initScalixFolder( KMail::FolderContentsType contentsType )
02131 {
02132
02133 KMFolderType type = mFolderType;
02134 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02135
02136 KMFolder* folder = 0;
02137
02138
02139 QStringList folderNames;
02140 QValueList<QGuardedPtr<KMFolder> > folderList;
02141 Q_ASSERT( kmkernel );
02142 Q_ASSERT( kmkernel->dimapFolderMgr() );
02143 kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
02144 QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
02145 for(; it != folderList.end(); ++it)
02146 {
02147 FolderStorage *storage = (*it)->storage();
02148
02149 if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
02150 KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
02151
02152 const QString attributes = imapFolder->folderAttributes();
02153 if ( attributes.contains( "X-SpecialFolder" ) ) {
02154 const Scalix::FolderAttributeParser parser( attributes );
02155 if ( contentsType == Scalix::Utils::scalixIdToContentsType( parser.folderClass() ) ) {
02156 folder = *it;
02157 break;
02158 }
02159 }
02160 }
02161 }
02162
02163 if ( !folder ) {
02164 return 0;
02165 } else {
02166 FolderInfo info = readFolderInfo( folder );
02167 mFolderInfoMap.insert( folder, info );
02168
02169 }
02170
02171 if( folder->canAccess() != 0 ) {
02172 KMessageBox::sorry(0, i18n("You do not have read/write permission to your folder.") );
02173 return 0;
02174 }
02175 folder->storage()->setContentsType( contentsType );
02176 folder->setSystemFolder( true );
02177 folder->storage()->writeConfig();
02178 folder->open( "scalixfolder" );
02179 connectFolder( folder );
02180 return folder;
02181 }
02182
02183 void KMailICalIfaceImpl::connectFolder( KMFolder* folder )
02184 {
02185
02186 disconnect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
02187 this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
02188 disconnect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
02189 this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
02190 disconnect( folder, SIGNAL( expunged( KMFolder* ) ),
02191 this, SLOT( slotRefreshFolder( KMFolder* ) ) );
02192 disconnect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
02193 this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
02194 disconnect( folder, SIGNAL( nameChanged() ),
02195 this, SLOT( slotFolderRenamed() ) );
02196 disconnect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
02197 this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
02198
02199
02200 connect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
02201 this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
02202 connect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
02203 this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
02204 connect( folder, SIGNAL( expunged( KMFolder* ) ),
02205 this, SLOT( slotRefreshFolder( KMFolder* ) ) );
02206 connect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
02207 this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
02208 connect( folder, SIGNAL( nameChanged() ),
02209 this, SLOT( slotFolderRenamed() ) );
02210 connect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
02211 this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
02212
02213 }
02214
02215 static void cleanupFolder( KMFolder* folder, KMailICalIfaceImpl* _this )
02216 {
02217 if( folder ) {
02218 folder->setSystemFolder( false );
02219 folder->disconnect( _this );
02220 folder->close("ifacefolder");
02221 }
02222 }
02223
02224 void KMailICalIfaceImpl::cleanup()
02225 {
02226 cleanupFolder( mContacts, this );
02227 cleanupFolder( mCalendar, this );
02228 cleanupFolder( mNotes, this );
02229 cleanupFolder( mTasks, this );
02230 cleanupFolder( mJournals, this );
02231
02232 mContacts = mCalendar = mNotes = mTasks = mJournals = 0;
02233 }
02234
02235 QString KMailICalIfaceImpl::folderPixmap( KFolderTreeItem::Type type ) const
02236 {
02237 if( !mUseResourceIMAP )
02238 return QString::null;
02239
02240 if( type == KFolderTreeItem::Contacts )
02241 return QString::fromLatin1( "kmgroupware_folder_contacts" );
02242 else if( type == KFolderTreeItem::Calendar )
02243 return QString::fromLatin1( "kmgroupware_folder_calendar" );
02244 else if( type == KFolderTreeItem::Notes )
02245 return QString::fromLatin1( "kmgroupware_folder_notes" );
02246 else if( type == KFolderTreeItem::Tasks )
02247 return QString::fromLatin1( "kmgroupware_folder_tasks" );
02248 else if( type == KFolderTreeItem::Journals )
02249 return QString::fromLatin1( "kmgroupware_folder_journals" );
02250
02251 return QString::null;
02252 }
02253
02254 static void reloadFolderTree()
02255 {
02256
02257 kmkernel->folderMgr()->contentsChanged();
02258 }
02259
02260
02261
02262
02263 static void vPartMicroParser( const QString& str, QString& s )
02264 {
02265 QString line;
02266 uint len = str.length();
02267
02268 for( uint i=0; i<len; ++i){
02269 if( str[i] == '\r' || str[i] == '\n' ){
02270 if( str[i] == '\r' )
02271 ++i;
02272 if( i+1 < len && str[i+1] == ' ' ){
02273
02274 ++i;
02275 }else{
02276
02277 if( line.startsWith( s ) ) {
02278 s = line.mid( s.length() + 1 );
02279 return;
02280 }
02281 line = "";
02282 }
02283 } else {
02284 line += str[i];
02285 }
02286 }
02287
02288
02289 s.truncate(0);
02290 }
02291
02292
02293 static QValueList<KMFolder*> findFolderByAnnotation( KMFolderDir* folderParentDir, const QString& annotation )
02294 {
02295 QValueList<KMFolder*> rv;
02296 QPtrListIterator<KMFolderNode> it( *folderParentDir );
02297 for ( ; it.current(); ++it ) {
02298 if ( !it.current()->isDir() ) {
02299 KMFolder* folder = static_cast<KMFolder *>( it.current() );
02300 if ( folder->folderType() == KMFolderTypeCachedImap ) {
02301 QString folderAnnotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
02302
02303 if ( folderAnnotation == annotation )
02304 rv.append( folder );
02305 }
02306 }
02307 }
02308 return rv;
02309 }
02310
02311 KMailICalIfaceImpl::StandardFolderSearchResult KMailICalIfaceImpl::findStandardResourceFolder( KMFolderDir* folderParentDir, KMail::FolderContentsType contentsType )
02312 {
02313 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
02314 {
02315
02316 QValueList<KMFolder*> folders = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) + ".default" );
02317 if ( !folders.isEmpty() )
02318 return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundAndStandard );
02319
02320
02321 folders = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) );
02322 if ( !folders.isEmpty() )
02323 return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundByType );
02324
02325
02326 KMFolderNode* node = folderParentDir->hasNamedFolder( localizedDefaultFolderName( contentsType ) );
02327 if ( node && !node->isDir() )
02328 return StandardFolderSearchResult( static_cast<KMFolder *>( node ), StandardFolderSearchResult::FoundByName );
02329
02330 kdDebug(5006) << "findStandardResourceFolder: found no resource folder for " << s_folderContentsType[contentsType].annotation << endl;
02331 return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02332 }
02333 else
02334 {
02335 KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
02336 unsigned int folderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
02337 if( folderLanguage > 3 ) folderLanguage = 0;
02338 KMFolderNode* node = folderParentDir->hasNamedFolder( folderName( itemType, folderLanguage ) );
02339 if ( !node || node->isDir() )
02340 return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02341 return StandardFolderSearchResult( static_cast<KMFolder*>( node ), StandardFolderSearchResult::FoundAndStandard );
02342 }
02343 }
02344
02345
02346
02347
02348
02349 bool KMailICalIfaceImpl::folderIsAlarmRelevant( const KMFolder *folder )
02350 {
02351 bool administerRights = true;
02352 bool relevantForOwner = true;
02353 bool relevantForEveryone = false;
02354 if ( folder->folderType() == KMFolderTypeImap ) {
02355 const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
02356 administerRights =
02357 imapFolder->userRightsState() != KMail::ACLJobs::Ok ||
02358 imapFolder->userRights() & KMail::ACLJobs::Administer;
02359 }
02360 if ( folder->folderType() == KMFolderTypeCachedImap ) {
02361 const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
02362 administerRights =
02363 dimapFolder->userRightsState() != KMail::ACLJobs::Ok ||
02364 dimapFolder->userRights() & KMail::ACLJobs::Administer;
02365 relevantForOwner = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor () == KMFolderCachedImap::IncForAdmins );
02366 relevantForEveryone = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor() == KMFolderCachedImap::IncForReaders );
02367 }
02368 #if 0
02369 kdDebug(5006) << k_funcinfo << endl;
02370 kdDebug(5006) << "Folder: " << folder->label() << " has administer rights: " << administerRights << endl;
02371 kdDebug(5006) << "and is relevant for owner: " << relevantForOwner << endl;
02372 kdDebug(5006) << "and relevant for everyone: " << relevantForEveryone << endl;
02373 #endif
02374 return ( administerRights && relevantForOwner ) || relevantForEveryone;
02375 }
02376
02377 void KMailICalIfaceImpl::setResourceQuiet(bool q)
02378 {
02379
02380 mResourceQuiet = q;
02381 }
02382
02383 bool KMailICalIfaceImpl::isResourceQuiet() const
02384 {
02385 return mResourceQuiet;
02386 }
02387
02388
02389 bool KMailICalIfaceImpl::addSubresource( const QString& resource,
02390 const QString& parent,
02391 const QString& contentsType )
02392 {
02393 kdDebug(5006) << "Adding subresource to parent: " << parent << " with name: " << resource << endl;
02394 kdDebug(5006) << "contents type: " << contentsType << endl;
02395 KMFolder *folder = findResourceFolder( parent );
02396 KMFolderDir *parentFolderDir = !parent.isEmpty() && folder ? folder->createChildFolder(): mFolderParentDir;
02397 if ( !parentFolderDir || parentFolderDir->hasNamedFolder( resource ) ) return false;
02398
02399 QString msg;
02400 if ( parentFolderDir->owner() && !parentFolderDir->owner()->isValidName( resource, msg ) ) {
02401 KMessageBox::error( 0, msg );
02402 return false;
02403 }
02404
02405 KMFolderType type = mFolderType;
02406 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02407
02408 KMFolder* newFolder = parentFolderDir->createFolder( resource, false, type );
02409 if ( !newFolder ) return false;
02410 if( mFolderType == KMFolderTypeImap )
02411 static_cast<KMFolderImap*>( folder->storage() )->createFolder( resource );
02412
02413 StorageFormat defaultFormat = GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
02414 setStorageFormat( newFolder, folder ? storageFormat( folder ) : defaultFormat );
02415 newFolder->storage()->setContentsType( folderContentsType( contentsType ) );
02416 newFolder->storage()->writeConfig();
02417 newFolder->open( "ical_subresource" );
02418 connectFolder( newFolder );
02419 reloadFolderTree();
02420
02421 return true;
02422 }
02423
02424 bool KMailICalIfaceImpl::removeSubresource( const QString& location )
02425 {
02426 kdDebug(5006) << k_funcinfo << endl;
02427
02428 KMFolder *folder = findResourceFolder( location );
02429
02430
02431
02432
02433 if ( !folder || isStandardResourceFolder( folder ) )
02434 return false;
02435
02436
02437
02438 subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), location );
02439 mExtraFolders.remove( location );
02440 folder->disconnect( this );
02441
02442 if ( folder->folderType() == KMFolderTypeImap )
02443 kmkernel->imapFolderMgr()->remove( folder );
02444 else if ( folder->folderType() == KMFolderTypeCachedImap ) {
02445
02446 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( folder->storage() );
02447 KMAcctCachedImap* acct = storage->account();
02448 if ( acct )
02449 acct->addDeletedFolder( folder );
02450 kmkernel->dimapFolderMgr()->remove( folder );
02451 }
02452 return true;
02453 }
02454
02455 void KMailICalIfaceImpl::syncFolder(KMFolder * folder) const
02456 {
02457 if ( kmkernel->isOffline() || !GlobalSettings::immediatlySyncDIMAPOnGroupwareChanges() )
02458 return;
02459 KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
02460 if ( !dimapFolder )
02461 return;
02462
02463 if ( dimapFolder->imapPath().isEmpty() ) {
02464 if ( folder->parent() && folder->parent()->owner() )
02465 syncFolder( folder->parent()->owner() );
02466 else
02467 return;
02468 }
02469 dimapFolder->account()->processNewMailInFolder( folder );
02470 }
02471
02472 KMailICalIface::Answer KMailICalIfaceImpl::messageReadyForUpdate( const QString &resource,
02473 Q_UINT32 sernum )
02474 {
02475 if ( sernum == 0 ) {
02476
02477 return Yes;
02478 }
02479
02480 KMFolder *folder = findResourceFolder( resource );
02481 if( !folder ) {
02482 kdError(5006) << "update(" << resource << ") : Not an IMAP resource folder" << endl;
02483 return Error;
02484 }
02485
02486 folder->open( "messageReadyForUpdate" );
02487
02488 const KMMessage *msg = findMessageBySerNum( sernum, folder );
02489
02490 if ( !msg ) {
02491 return Error;
02492 }
02493
02494 KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
02495 Answer answer = Yes;
02496 if ( dimapFolder ) {
02497 if ( msg->transferInProgress() || !dimapFolder->isInInitialState() ) {
02498 answer = No;
02499 }
02500 }
02501
02502 folder->close( "messageReadyForUpdate" );
02503 return answer;
02504 }
02505
02506 #include "kmailicalifaceimpl.moc"