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 KMMessage* msg = 0;
00851 if ( sernum != 0 ) {
00852 if ( storageFormat( f ) == StorageXML ) {
00853 msg = findMessageBySerNum( sernum, f, subject );
00854 } else {
00855 msg = findMessageBySerNum( sernum, f );
00856 }
00857 if ( !msg ) return 0;
00858
00859 KMMessage* newMsg = new KMMessage( *msg );
00860 newMsg->setSubject( subject );
00861 QMap<QCString, QString>::ConstIterator ith = customHeaders.begin();
00862 const QMap<QCString, QString>::ConstIterator ithEnd = customHeaders.begin();
00863 for ( ; ith != ithEnd ; ++ith )
00864 newMsg->setHeaderField( ith.key(), ith.data() );
00865 newMsg->setParent( 0 );
00866
00867
00868
00869 for( QStringList::ConstIterator it = deletedAttachments.begin();
00870 it != deletedAttachments.end();
00871 ++it ){
00872 if( !deleteAttachment( *newMsg, *it ) ){
00873
00874 }
00875 }
00876
00877 const KMail::FolderContentsType t = f->storage()->contentsType();
00878 const QCString type = msg->typeStr();
00879 const QCString subtype = msg->subtypeStr();
00880 const bool messageWasIcalVcardFormat = ( type.lower() == "text" &&
00881 ( subtype.lower() == "calendar" || subtype.lower() == "x-vcard" ) );
00882
00883 if ( storageFormat( f ) == StorageIcalVcard ) {
00884
00885 if ( !messageWasIcalVcardFormat ) {
00886 setIcalVcardContentTypeHeader( newMsg, t, f );
00887 }
00888 newMsg->setBodyEncoded( plainTextBody.utf8() );
00889 } else if ( storageFormat( f ) == StorageXML ) {
00890 if ( messageWasIcalVcardFormat ) {
00891
00892
00893 setXMLContentTypeHeader( newMsg, plainTextBody );
00894 }
00895
00896
00897 QStringList::ConstIterator iturl = attachmentURLs.begin();
00898 QStringList::ConstIterator itmime = attachmentMimetypes.begin();
00899 QStringList::ConstIterator itname = attachmentNames.begin();
00900 for( ;
00901 iturl != attachmentURLs.end()
00902 && itmime != attachmentMimetypes.end()
00903 && itname != attachmentNames.end();
00904 ++iturl, ++itname, ++itmime ){
00905 bool byname = !(*itmime).startsWith( "application/x-vnd.kolab." );
00906 if( !updateAttachment( *newMsg, *iturl, *itname, *itmime, byname ) ){
00907 kdDebug(5006) << "Attachment error, can not update attachment " << *iturl << endl;
00908 break;
00909 }
00910 }
00911 }
00912
00913
00914
00915
00916 newMsg->cleanupHeader();
00917
00918
00919
00920 deleteMsg( msg );
00921
00922 if ( f->addMsg( newMsg ) == 0 ) {
00923
00924 rc = newMsg->getMsgSerNum();
00925 kdDebug(5006) << "forget about " << sernum << ", it's " << rc << " now" << endl;
00926 }
00927 addFolderChange( f, Contents );
00928 syncFolder( f );
00929 } else {
00930
00931 rc = addIncidenceKolab( *f, subject, plainTextBody, customHeaders,
00932 attachmentURLs,
00933 attachmentNames,
00934 attachmentMimetypes );
00935 }
00936
00937 f->close("ifaceupdate");
00938 return rc;
00939 }
00940
00941 KURL KMailICalIfaceImpl::getAttachment( const QString& resource,
00942 Q_UINT32 sernum,
00943 const QString& filename )
00944 {
00945
00946
00947
00948 if( !mUseResourceIMAP )
00949 return KURL();
00950
00951 kdDebug(5006) << "KMailICalIfaceImpl::getAttachment( "
00952 << resource << ", " << sernum << ", " << filename << " )\n";
00953
00954
00955 KMFolder* f = findResourceFolder( resource );
00956 if( !f ) {
00957 kdError(5006) << "getAttachment(" << resource << ") : Not an IMAP resource folder" << endl;
00958 return KURL();
00959 }
00960 if ( storageFormat( f ) != StorageXML ) {
00961 kdError(5006) << "getAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
00962 return KURL();
00963 }
00964
00965 KURL url;
00966
00967 bool bOK = false;
00968 bool quiet = mResourceQuiet;
00969 mResourceQuiet = true;
00970
00971 KMMessage* msg = findMessageBySerNum( sernum, f );
00972 if( msg ) {
00973
00974
00975 DwBodyPart* part = findBodyPart( *msg, filename );
00976 if ( part ) {
00977
00978 KMMessagePart aPart;
00979 msg->bodyPart( part, &aPart );
00980 QByteArray rawData( aPart.bodyDecodedBinary() );
00981
00982 KTempFile file;
00983 file.file()->writeBlock( rawData.data(), rawData.size() );
00984
00985 url.setPath( file.name() );
00986
00987 bOK = true;
00988 }
00989
00990 if( !bOK ){
00991 kdDebug(5006) << "Attachment " << filename << " not found." << endl;
00992 }
00993 }else{
00994 kdDebug(5006) << "Message not found." << endl;
00995 }
00996
00997 mResourceQuiet = quiet;
00998 return url;
00999 }
01000
01001 QString KMailICalIfaceImpl::attachmentMimetype( const QString & resource,
01002 Q_UINT32 sernum,
01003 const QString & filename )
01004 {
01005 if( !mUseResourceIMAP )
01006 return QString();
01007 KMFolder* f = findResourceFolder( resource );
01008 if( !f || storageFormat( f ) != StorageXML ) {
01009 kdError(5006) << "attachmentMimetype(" << resource << ") : Wrong folder" << endl;
01010 return QString();
01011 }
01012
01013 KMMessage* msg = findMessageBySerNum( sernum, f );
01014 if( msg ) {
01015
01016 DwBodyPart* part = findBodyPart( *msg, filename );
01017 if ( part ) {
01018 KMMessagePart kmPart;
01019 msg->bodyPart( part, &kmPart );
01020 return QString( kmPart.typeStr() ) + "/" + QString( kmPart.subtypeStr() );
01021 } else {
01022 kdDebug(5006) << "Attachment " << filename << " not found." << endl;
01023 }
01024 } else {
01025 kdDebug(5006) << "Message not found." << endl;
01026 }
01027
01028 return QString();
01029 }
01030
01031 QStringList KMailICalIfaceImpl::listAttachments(const QString & resource, Q_UINT32 sernum)
01032 {
01033 QStringList rv;
01034 if( !mUseResourceIMAP )
01035 return rv;
01036
01037
01038 KMFolder* f = findResourceFolder( resource );
01039 if( !f ) {
01040 kdError(5006) << "listAttachments(" << resource << ") : Not an IMAP resource folder" << endl;
01041 return rv;
01042 }
01043 if ( storageFormat( f ) != StorageXML ) {
01044 kdError(5006) << "listAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
01045 return rv;
01046 }
01047
01048 KMMessage* msg = findMessageBySerNum( sernum, f );
01049 if( msg ) {
01050 for ( DwBodyPart* part = msg->getFirstDwBodyPart(); part; part = part->Next() ) {
01051 if ( part->hasHeaders() ) {
01052 QString name;
01053 DwMediaType& contentType = part->Headers().ContentType();
01054 if ( QString( contentType.SubtypeStr().c_str() ).startsWith( "x-vnd.kolab." )
01055 || QString( contentType.SubtypeStr().c_str() ).contains( "tnef" ) )
01056 continue;
01057 if ( !part->Headers().ContentDisposition().Filename().empty() )
01058 name = part->Headers().ContentDisposition().Filename().c_str();
01059 else if ( !contentType.Name().empty() )
01060 name = contentType.Name().c_str();
01061 if ( !name.isEmpty() )
01062 rv.append( name );
01063 }
01064 }
01065 } else {
01066 kdDebug(5006) << "Message not found." << endl;
01067 }
01068
01069 return rv;
01070 }
01071
01072
01073
01074
01075
01076
01077
01078
01079 void KMailICalIfaceImpl::slotFolderRemoved( KMFolder* folder )
01080 {
01081
01082
01083 folderContentsTypeChanged( folder, KMail::ContentsTypeMail );
01084 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01085 configGroup.deleteEntry( folder->idString() + "-storageFormat" );
01086 configGroup.deleteEntry( folder->idString() + "-changes" );
01087 }
01088
01089
01090 void KMailICalIfaceImpl::slotIncidenceAdded( KMFolder* folder,
01091 Q_UINT32 sernum )
01092 {
01093 if( mResourceQuiet || !mUseResourceIMAP ) {
01094
01095 return;
01096 }
01097
01098
01099
01100 QString type = folderContentsType( folder->storage()->contentsType() );
01101 if( type.isEmpty() ) {
01102 kdError(5006) << "Not an IMAP resource folder" << endl;
01103 return;
01104 }
01105
01106 int i = 0;
01107 KMFolder* aFolder = 0;
01108 KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
01109 assert( folder == aFolder );
01110
01111 bool unget = !folder->isMessage( i );
01112 QString s;
01113 QString uid( "UID" );
01114 KMMessage *msg = folder->getMsg( i );
01115 if( !msg ) return;
01116 if( msg->isComplete() ) {
01117
01118 bool ok = false;
01119 StorageFormat format = storageFormat( folder );
01120 switch( format ) {
01121 case StorageIcalVcard:
01122
01123 ok = vPartFoundAndDecoded( msg, s );
01124 if ( ok )
01125 vPartMicroParser( s, uid );
01126 break;
01127 case StorageXML:
01128
01129 if ( kolabXMLFoundAndDecoded( *msg,
01130 folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
01131 uid = msg->subject();
01132 ok = true;
01133 }
01134 break;
01135 }
01136 if ( !ok ) {
01137 if ( unget )
01138 folder->unGetMsg( i );
01139 return;
01140 }
01141 const Q_UINT32 sernum = msg->getMsgSerNum();
01142 mUIDToSerNum.insert( uid, sernum );
01143
01144
01145 if ( mInTransit.contains( uid ) ) {
01146 mInTransit.remove( uid );
01147 }
01148 incidenceAdded( type, folder->location(), sernum, format, s );
01149 } else {
01150
01151
01152 if ( unget ) mTheUnGetMes.insert( msg->getMsgSerNum(), true );
01153 FolderJob *job = msg->parent()->createJob( msg );
01154 connect( job, SIGNAL( messageRetrieved( KMMessage* ) ),
01155 this, SLOT( slotMessageRetrieved( KMMessage* ) ) );
01156 job->start();
01157 return;
01158 }
01159 if( unget ) folder->unGetMsg(i);
01160 }
01161
01162
01163 void KMailICalIfaceImpl::slotIncidenceDeleted( KMFolder* folder,
01164 Q_UINT32 sernum )
01165 {
01166 if( mResourceQuiet || !mUseResourceIMAP ) {
01167
01168 return;
01169 }
01170
01171
01172 QString type = folderContentsType( folder->storage()->contentsType() );
01173
01174 if( !type.isEmpty() ) {
01175
01176 int i = 0;
01177 KMFolder* aFolder = 0;
01178 KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
01179 assert( folder == aFolder );
01180
01181
01182 bool unget = !folder->isMessage( i );
01183 QString s;
01184 bool ok = false;
01185 KMMessage* msg = folder->getMsg( i );
01186 QString uid( "UID" );
01187 switch( storageFormat( folder ) ) {
01188 case StorageIcalVcard:
01189 if( vPartFoundAndDecoded( msg, s ) ) {
01190 vPartMicroParser( s, uid );
01191 ok = true;
01192 }
01193 break;
01194 case StorageXML:
01195 if ( kolabXMLFoundAndDecoded( *msg, folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
01196 uid = msg->subject();
01197 ok = true;
01198 }
01199 break;
01200 }
01201 if ( ok ) {
01202 kdDebug(5006) << "Emitting DCOP signal incidenceDeleted( "
01203 << type << ", " << folder->location() << ", " << uid
01204 << " )" << endl;
01205 incidenceDeleted( type, folder->location(), uid, sernum );
01206 }
01207 if( unget ) folder->unGetMsg(i);
01208 } else
01209 kdError(5006) << "Not a groupware folder" << endl;
01210 }
01211
01212
01213 void KMailICalIfaceImpl::slotRefresh( const QString& type )
01214 {
01215 if( mUseResourceIMAP ) {
01216 signalRefresh( type, QString::null );
01217 kdDebug(5006) << "Emitting DCOP signal signalRefresh( " << type << " )" << endl;
01218 }
01219 }
01220
01221
01222 void KMailICalIfaceImpl::slotRefreshFolder( KMFolder* folder)
01223 {
01224
01225
01226
01227 if( mUseResourceIMAP && folder ) {
01228 if( folder == mCalendar || folder == mContacts
01229 || folder == mNotes || folder == mTasks
01230 || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01231
01232 KMail::FolderContentsType ct = folder->storage()->contentsType();
01233 slotRefresh( s_folderContentsType[ct].contentsTypeStr );
01234 }
01235 }
01236 }
01237
01238
01239
01240
01241
01242 KMFolder* KMailICalIfaceImpl::folderFromType( const QString& type,
01243 const QString& folder )
01244 {
01245 if( mUseResourceIMAP ) {
01246 KMFolder* f = 0;
01247 if ( !folder.isEmpty() ) {
01248 f = extraFolder( type, folder );
01249 if ( f )
01250 return f;
01251 }
01252
01253 if( type == "Calendar" ) f = mCalendar;
01254 else if( type == "Contact" ) f = mContacts;
01255 else if( type == "Note" ) f = mNotes;
01256 else if( type == "Task" || type == "Todo" ) f = mTasks;
01257 else if( type == "Journal" ) f = mJournals;
01258
01259 if ( f && ( folder.isEmpty() || folder == f->location() ) )
01260 return f;
01261
01262 kdError(5006) << "No folder ( " << type << ", " << folder << " )\n";
01263 }
01264
01265 return 0;
01266 }
01267
01268
01269
01270
01271 bool KMailICalIfaceImpl::isResourceFolder( KMFolder* folder ) const
01272 {
01273 return mUseResourceIMAP && folder &&
01274 ( isStandardResourceFolder( folder ) || mExtraFolders.find( folder->location() )!=0 );
01275 }
01276
01277 bool KMailICalIfaceImpl::isStandardResourceFolder( KMFolder* folder ) const
01278 {
01279 return ( folder == mCalendar || folder == mTasks || folder == mJournals ||
01280 folder == mNotes || folder == mContacts );
01281 }
01282
01283 bool KMailICalIfaceImpl::hideResourceFolder( KMFolder* folder ) const
01284 {
01285 return mHideFolders && isResourceFolder( folder );
01286 }
01287
01288 bool KMailICalIfaceImpl::hideResourceAccountRoot( KMFolder* folder ) const
01289 {
01290 KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
01291 bool hide = dimapFolder && mHideFolders
01292 && (int)dimapFolder->account()->id() == GlobalSettings::self()->theIMAPResourceAccount()
01293 && GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount();
01294 return hide;
01295
01296 }
01297
01298 KFolderTreeItem::Type KMailICalIfaceImpl::folderType( KMFolder* folder ) const
01299 {
01300 if( mUseResourceIMAP && folder ) {
01301 if( folder == mCalendar || folder == mContacts
01302 || folder == mNotes || folder == mTasks
01303 || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01304 KMail::FolderContentsType ct = folder->storage()->contentsType();
01305 return s_folderContentsType[ct].treeItemType;
01306 }
01307 }
01308
01309 return KFolderTreeItem::Other;
01310 }
01311
01312
01313
01314 static QMap<KFolderTreeItem::Type,QString> folderNames[4];
01315 QString KMailICalIfaceImpl::folderName( KFolderTreeItem::Type type, int language ) const
01316 {
01317
01318 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
01319 language = 0;
01320
01321 static bool folderNamesSet = false;
01322 if( !folderNamesSet ) {
01323 folderNamesSet = true;
01324
01325
01326
01327
01328 folderNames[0][KFolderTreeItem::Calendar] = QString::fromLatin1("Calendar");
01329 folderNames[0][KFolderTreeItem::Tasks] = QString::fromLatin1("Tasks");
01330 folderNames[0][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01331 folderNames[0][KFolderTreeItem::Contacts] = QString::fromLatin1("Contacts");
01332 folderNames[0][KFolderTreeItem::Notes] = QString::fromLatin1("Notes");
01333
01334
01335 folderNames[1][KFolderTreeItem::Calendar] = QString::fromLatin1("Kalender");
01336 folderNames[1][KFolderTreeItem::Tasks] = QString::fromLatin1("Aufgaben");
01337 folderNames[1][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01338 folderNames[1][KFolderTreeItem::Contacts] = QString::fromLatin1("Kontakte");
01339 folderNames[1][KFolderTreeItem::Notes] = QString::fromLatin1("Notizen");
01340
01341
01342 folderNames[2][KFolderTreeItem::Calendar] = QString::fromLatin1("Calendrier");
01343
01344 folderNames[2][KFolderTreeItem::Tasks] = QString::fromLatin1("T\342ches");
01345 folderNames[2][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01346 folderNames[2][KFolderTreeItem::Contacts] = QString::fromLatin1("Contacts");
01347 folderNames[2][KFolderTreeItem::Notes] = QString::fromLatin1("Notes");
01348
01349
01350 folderNames[3][KFolderTreeItem::Calendar] = QString::fromLatin1("Agenda");
01351 folderNames[3][KFolderTreeItem::Tasks] = QString::fromLatin1("Taken");
01352 folderNames[3][KFolderTreeItem::Journals] = QString::fromLatin1("Logboek");
01353 folderNames[3][KFolderTreeItem::Contacts] = QString::fromLatin1("Contactpersonen");
01354 folderNames[3][KFolderTreeItem::Notes] = QString::fromLatin1("Notities");
01355 }
01356
01357 if( language < 0 || language > 3 ) {
01358 return folderNames[mFolderLanguage][type];
01359 }
01360 else {
01361 return folderNames[language][type];
01362 }
01363 }
01364
01365
01366
01367 KMMessage *KMailICalIfaceImpl::findMessageByUID( const QString& uid, KMFolder* folder )
01368 {
01369 if( !folder || !mUIDToSerNum.contains( uid ) ) return 0;
01370 int i;
01371 KMFolder *aFolder;
01372 KMMsgDict::instance()->getLocation( mUIDToSerNum[uid], &aFolder, &i );
01373 Q_ASSERT( aFolder == folder );
01374 return folder->getMsg( i );
01375 }
01376
01377
01378 KMMessage *KMailICalIfaceImpl::findMessageBySerNum( Q_UINT32 serNum, KMFolder* folder, const QString& subject )
01379 {
01380 if( !folder ) return 0;
01381
01382 KMMessage *message = 0;
01383 KMFolder* aFolder = 0;
01384 int index;
01385 KMMsgDict::instance()->getLocation( serNum, &aFolder, &index );
01386
01387 if( aFolder && aFolder != folder ) {
01388 kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) found it in folder " << aFolder->location() << ", expected " << folder->location() << endl;
01389 } else {
01390 if( aFolder )
01391 message = aFolder->getMsg( index );
01392 if (!message)
01393 kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) invalid serial number\n" << endl;
01394 }
01395
01396
01397
01398
01399
01400
01401
01402 if ( !subject.isEmpty() ) {
01403 if ( message->subject() != subject ) {
01404
01405 kdWarning(5006) << k_funcinfo << " Subject check failed!" << endl
01406 << "Got: " << message->subject() << endl
01407 << "Expected: " << subject << endl;
01408 sleep( 1 );
01409 message = aFolder->getMsg( index );
01410 if ( !message ) {
01411 kdWarning(5006) << "Second getMsg returned 0" << endl;
01412 return 0;
01413 }
01414 if ( message->subject() != subject ) {
01415 kdWarning(5006) << "Still got the wrong message: " << message->subject() << endl;
01416 KMFolderCachedImap * cimapFolder = dynamic_cast<KMFolderCachedImap *> ( aFolder->storage() );
01417 if ( cimapFolder != NULL ) {
01418 cimapFolder->markForReindexing();
01419 } else {
01420
01421 kdWarning(5006) << "Folder is not a cached IMAP folder" << endl;
01422 }
01423 const QString errMsg = i18n("<qt>Kontact has detected a corruption in the folder: <br/> %1 <br/>"
01424 "Your current changes could not be saved.<br/><br/>"
01425 "It is <b>strongly</b> recommended that you restart Kontact now.<br/>"
01426 "Quit now?</qt>").arg(folder->prettyURL());
01427 if ( KMessageBox::warningYesNo( 0, errMsg, i18n("Invalid state detected") ) == KMessageBox::Yes ) {
01428 qApp->quit();
01429 } else {
01430 return 0;
01431 }
01432 } else {
01433 kdDebug(5006) << "Got the right message now, phew" << endl;
01434 }
01435 }
01436 }
01437 return message;
01438 }
01439
01440 void KMailICalIfaceImpl::deleteMsg( KMMessage *msg )
01441 {
01442 if( !msg ) return;
01443
01444
01445 KMFolder *srcFolder = msg->parent();
01446 int idx = srcFolder->find(msg);
01447 assert(idx != -1);
01448
01449 srcFolder->ignoreJobsForMessage( msg );
01450 if ( !msg->transferInProgress() ) {
01451 srcFolder->removeMsg(idx);
01452 delete msg;
01453 } else {
01454 kdDebug(5006) << k_funcinfo << "DEBUG Message cannot be deleted now because it is currently in use " << msg << endl;
01455 msg->deleteWhenUnused();
01456 }
01457 addFolderChange( srcFolder, Contents );
01458 }
01459
01460 void KMailICalIfaceImpl::folderContentsTypeChanged( KMFolder* folder,
01461 KMail::FolderContentsType contentsType )
01462 {
01463 if ( !mUseResourceIMAP )
01464 return;
01465
01466
01467
01468
01469 if ( isStandardResourceFolder( folder ) )
01470 return;
01471
01472
01473 const QString location = folder->location();
01474 ExtraFolder* ef = mExtraFolders.find( location );
01475 if ( ef && ef->folder ) {
01476
01477 subresourceDeleted(folderContentsType( folder->storage()->contentsType() ), location );
01478
01479 if ( contentsType == KMail::ContentsTypeMail ) {
01480
01481 mExtraFolders.remove( location );
01482 folder->disconnect( this );
01483 return;
01484 }
01485
01486 } else {
01487 if ( ef && !ef->folder )
01488 mExtraFolders.remove( location );
01489 if ( contentsType == KMail::ContentsTypeMail )
01490 return;
01491
01492
01493
01494 ef = new ExtraFolder( folder );
01495 mExtraFolders.insert( location, ef );
01496
01497 FolderInfo info = readFolderInfo( folder );
01498 mFolderInfoMap.insert( folder, info );
01499
01500
01501
01502
01503
01504
01505 if ( folder->folderType() == KMFolderTypeCachedImap ) {
01506 QString annotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
01507 kdDebug(5006) << "folderContentsTypeChanged: " << folder->name() << " has annotation " << annotation << endl;
01508 if ( annotation == QString( s_folderContentsType[contentsType].annotation ) + ".default" )
01509 folder->setLabel( localizedDefaultFolderName( contentsType ) );
01510 }
01511
01512 connectFolder( folder );
01513 }
01514
01515 subresourceAdded( folderContentsType( contentsType ), location, subresourceLabelForPresentation(folder),
01516 folder->isWritable(), folderIsAlarmRelevant( folder ) );
01517 }
01518
01519 KMFolder* KMailICalIfaceImpl::extraFolder( const QString& type,
01520 const QString& folder )
01521 {
01522
01523
01524 int t = folderContentsType( type );
01525 if ( t < 1 || t > 5 )
01526 return 0;
01527
01528 ExtraFolder* ef = mExtraFolders.find( folder );
01529 if ( ef && ef->folder && ef->folder->storage()->contentsType() == t )
01530 return ef->folder;
01531
01532 return 0;
01533 }
01534
01535 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( KMFolder* folder ) const
01536 {
01537 FolderInfoMap::ConstIterator it = mFolderInfoMap.find( folder );
01538 if ( it != mFolderInfoMap.end() )
01539 return (*it).mStorageFormat;
01540 return globalStorageFormat();
01541 }
01542
01543 void KMailICalIfaceImpl::setStorageFormat( KMFolder* folder, StorageFormat format )
01544 {
01545 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01546 if ( it != mFolderInfoMap.end() ) {
01547 (*it).mStorageFormat = format;
01548 } else {
01549 FolderInfo info( format, NoChange );
01550 mFolderInfoMap.insert( folder, info );
01551 }
01552 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01553 configGroup.writeEntry( folder->idString() + "-storageFormat",
01554 format == StorageXML ? "xml" : "icalvcard" );
01555 }
01556
01557 void KMailICalIfaceImpl::addFolderChange( KMFolder* folder, FolderChanges changes )
01558 {
01559 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01560 if ( it != mFolderInfoMap.end() ) {
01561 (*it).mChanges = static_cast<FolderChanges>( (*it).mChanges | changes );
01562 } else {
01563 kdDebug(5006) << "addFolderChange: nothing known about folder " << folder->location() << endl;
01564 }
01565 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01566 configGroup.writeEntry( folder->idString() + "-changes", (*it).mChanges );
01567 }
01568
01569 KMailICalIfaceImpl::FolderInfo KMailICalIfaceImpl::readFolderInfo( const KMFolder * const folder ) const
01570 {
01571 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01572 QString str = configGroup.readEntry( folder->idString() + "-storageFormat", "unset" );
01573 FolderInfo info;
01574 if ( str == "unset" ) {
01575 info.mStorageFormat = globalStorageFormat();
01576 configGroup.writeEntry( folder->idString() + "-storageFormat",
01577 info.mStorageFormat == StorageXML ? "xml" : "icalvcard" );
01578 } else {
01579 info.mStorageFormat = ( str == "xml" ) ? StorageXML : StorageIcalVcard;
01580 }
01581 info.mChanges = (FolderChanges) configGroup.readNumEntry( folder->idString() + "-changes" );
01582 return info;
01583 }
01584
01585
01586 void KMailICalIfaceImpl::folderSynced( KMFolder* folder, const KURL& folderURL )
01587 {
01588 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01589 if ( it != mFolderInfoMap.end() && (*it).mChanges ) {
01590 handleFolderSynced( folder, folderURL, (*it).mChanges );
01591 (*it).mChanges = NoChange;
01592 }
01593 }
01594
01595 void KMailICalIfaceImpl::handleFolderSynced( KMFolder* folder,
01596 const KURL& folderURL,
01597 int _changes )
01598 {
01599
01600
01601
01602
01603 if ( ( _changes & KMailICalIface::Contents ) ||
01604 ( _changes & KMailICalIface::ACL ) ) {
01605 if ( storageFormat( folder ) == StorageXML && folder->storage()->contentsType() == KMail::ContentsTypeCalendar )
01606 triggerKolabFreeBusy( folderURL, true );
01607 }
01608 }
01609
01610 void KMailICalIfaceImpl::folderDeletedOnServer( const KURL& folderURL )
01611 {
01612 triggerKolabFreeBusy( folderURL, false );
01613 }
01614
01615 void KMailICalIfaceImpl::triggerKolabFreeBusy( const KURL& folderURL, bool report )
01616 {
01617
01618
01619
01620 KURL httpURL( folderURL );
01621
01622 httpURL.setProtocol( "https" );
01623 httpURL.setPort( 0 );
01624
01625
01626 QString path = folderURL.path( -1 );
01627 Q_ASSERT( path.startsWith( "/" ) );
01628 int secondSlash = path.find( '/', 1 );
01629 if ( secondSlash == -1 ) {
01630 kdWarning() << "KCal::ResourceKolab::fromKMailFolderSynced path is too short: " << path << endl;
01631 return;
01632 }
01633 if ( path.startsWith( "/INBOX/", false ) ) {
01634
01635 path = path.mid( secondSlash );
01636 path.prepend( folderURL.user() );
01637 } else {
01638
01639
01640 path = path.mid( secondSlash );
01641 }
01642
01643 if ( path.startsWith( "/" ) )
01644 httpURL.setPath( "/freebusy/trigger" + path + ".pfb" );
01645 else
01646 httpURL.setPath( "/freebusy/trigger/" + path + ".pfb" );
01647
01648 httpURL.setQuery( QString::null );
01649
01650 httpURL = KURL( httpURL.url(0,106), 106 );
01651 kdDebug() << "Triggering PFB update for " << folderURL << " : getting " << httpURL << endl;
01652
01653 if ( report ) {
01654 KIO::Job* job = KIO::get( httpURL, false, false );
01655 job->addMetaData( "errorPage", "false" );
01656 connect( job, SIGNAL( result( KIO::Job* ) ), SLOT( slotFreeBusyTriggerResult( KIO::Job* ) ) );
01657 }
01658 }
01659
01660 void KMailICalIfaceImpl::slotFreeBusyTriggerResult( KIO::Job *job )
01661 {
01662 if ( job->error() ) {
01663 KURL url( job->errorText() );
01664 KMessageBox::sorry(0, i18n("Could not trigger Free/Busy information update: %1.").arg( url.prettyURL() ) );
01665 }
01666 }
01667
01668 void KMailICalIfaceImpl::slotFolderPropertiesChanged( KMFolder* folder )
01669 {
01670 if ( isResourceFolder( folder ) ) {
01671 const QString location = folder->location();
01672 const QString contentsTypeStr = folderContentsType( folder->storage()->contentsType() );
01673 subresourceDeleted( contentsTypeStr, location );
01674
01675 subresourceAdded( contentsTypeStr, location, subresourceLabelForPresentation( folder ),
01676 folder->isWritable(), folderIsAlarmRelevant( folder ) );
01677 }
01678 }
01679
01680
01681 void KMailICalIfaceImpl::slotFolderRenamed()
01682 {
01683 const KMFolder* folder = static_cast<const KMFolder *>( sender() );
01684 slotFolderPropertiesChanged( const_cast<KMFolder*>( folder ) );
01685 }
01686
01687 void KMailICalIfaceImpl::slotFolderLocationChanged( const QString &oldLocation,
01688 const QString &newLocation )
01689 {
01690 KMFolder *folder = findResourceFolder( oldLocation );
01691 ExtraFolder* ef = mExtraFolders.find( oldLocation );
01692 if ( ef ) {
01693
01694 mExtraFolders.setAutoDelete( false );
01695 mExtraFolders.remove( oldLocation );
01696 mExtraFolders.setAutoDelete( true );
01697 mExtraFolders.insert( newLocation, ef );
01698 }
01699 if ( folder )
01700 subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), oldLocation );
01701
01702 }
01703
01704 KMFolder* KMailICalIfaceImpl::findResourceFolder( const QString& resource )
01705 {
01706
01707 if( mCalendar && mCalendar->location() == resource )
01708 return mCalendar;
01709 if ( mContacts && mContacts->location() == resource )
01710 return mContacts;
01711 if ( mNotes && mNotes->location() == resource )
01712 return mNotes;
01713 if ( mTasks && mTasks->location() == resource )
01714 return mTasks;
01715 if ( mJournals && mJournals->location() == resource )
01716 return mJournals;
01717
01718
01719 ExtraFolder* ef = mExtraFolders.find( resource );
01720 if ( ef )
01721 return ef->folder;
01722
01723
01724 return 0;
01725 }
01726
01727 QString KMailICalIfaceImpl::dimapFolderAccountName( const QString &folderPath )
01728 {
01729 QString name;
01730 KMFolder *f = findResourceFolder( folderPath );
01731 if ( f ) {
01732 if ( f->storage() && static_cast<const KMFolderCachedImap*>( f->storage() )->account() ) {
01733 name = static_cast<const KMFolderCachedImap*>( f->storage() )->account()->name();
01734 }
01735 }
01736 return name;
01737 }
01738
01739 void KMailICalIfaceImpl::changeResourceUIName( const QString &folderPath, const QString &newName )
01740 {
01741 kdDebug() << "Folder path " << folderPath << endl;
01742 KMFolder *f = findResourceFolder( folderPath );
01743 if ( f ) {
01744 KMailICalIfaceImpl::getResourceMap()->insert( folderPath, newName );
01745 kmkernel->folderMgr()->renameFolder( f, newName );
01746 KConfigGroup configGroup( kmkernel->config(), "Resource UINames" );
01747 configGroup.writeEntry( folderPath, newName );
01748 }
01749 }
01750
01751
01752 static void createFolderList( QStringList &folderNames, QValueList<QGuardedPtr<KMFolder> > &folderList )
01753 {
01754 QStringList dimapFolderNames;
01755 QStringList localFolderNames;
01756 QValueList<QGuardedPtr<KMFolder> > dimapFolderList;
01757 QValueList<QGuardedPtr<KMFolder> > localFolderList;
01758 kmkernel->dimapFolderMgr()->createFolderList( &dimapFolderNames, &dimapFolderList );
01759 kmkernel->folderMgr()->createFolderList( &localFolderNames, &localFolderList );
01760 folderNames += dimapFolderNames;
01761 folderNames += localFolderNames;
01762 folderList += dimapFolderList;
01763 folderList += localFolderList;
01764 }
01765
01766
01767
01768
01769
01770 void KMailICalIfaceImpl::readConfig()
01771 {
01772 bool enabled = GlobalSettings::self()->theIMAPResourceEnabled() &&
01773 ( GlobalSettings::self()->theIMAPResourceAccount() != 0 );
01774
01775 if( !enabled ) {
01776 if( mUseResourceIMAP == true ) {
01777
01778 mUseResourceIMAP = false;
01779 cleanup();
01780 reloadFolderTree();
01781 }
01782 return;
01783 }
01784 mUseResourceIMAP = enabled;
01785
01786
01787 const bool hideFolders = GlobalSettings::self()->hideGroupwareFolders();
01788 QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01789
01790
01791 KMFolderDir* folderParentDir;
01792 KMFolderType folderType;
01793 KMFolder* folderParent = kmkernel->findFolderById( parentName );
01794 if( folderParent == 0 ) {
01795
01796
01797 kdDebug(5006) << "Groupware folder " << parentName << " not found. Groupware functionality disabled" << endl;
01798
01799 KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01800 Q_ASSERT( account );
01801 if ( account ) {
01802
01803 disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01804 this, SLOT( slotCheckDone() ) );
01805 connect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01806 this, SLOT( slotCheckDone() ) );
01807 }
01808 mUseResourceIMAP = false;
01809
01810 mCalendar = 0;
01811 mTasks = 0;
01812 mJournals = 0;
01813 mContacts = 0;
01814 mNotes = 0;
01815 return;
01816 } else {
01817 folderParentDir = folderParent->createChildFolder();
01818 folderType = folderParent->folderType();
01819 }
01820
01821 KMAcctCachedImap::GroupwareType groupwareType = dynamic_cast<KMFolderCachedImap *>( folderParent->storage() )->account()->groupwareType();
01822
01823 if ( groupwareType == KMAcctCachedImap::GroupwareKolab ) {
01824
01825
01826 bool noneFound = true;
01827 bool mustFix = false;
01828 QValueVector<StandardFolderSearchResult> results( KMail::ContentsTypeLast + 1 );
01829 for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01830 if ( i != KMail::ContentsTypeMail ) {
01831 results[i] = findStandardResourceFolder( folderParentDir, static_cast<KMail::FolderContentsType>(i) );
01832 if ( results[i].found == StandardFolderSearchResult::FoundAndStandard )
01833 noneFound = false;
01834 else if ( results[i].found == StandardFolderSearchResult::FoundByType ||
01835 results[i].found == StandardFolderSearchResult::FoundByName ) {
01836 mustFix = true;
01837 noneFound = false;
01838 } else
01839 mustFix = true;
01840 }
01841 }
01842
01843
01844 if( mUseResourceIMAP && !noneFound && !mustFix && mFolderParentDir == folderParentDir
01845 && mFolderType == folderType ) {
01846
01847 if ( hideFolders != mHideFolders ) {
01848
01849 mHideFolders = hideFolders;
01850 reloadFolderTree();
01851 }
01852 return;
01853 }
01854
01855 if( noneFound || mustFix ) {
01856 QString msg;
01857 QString parentFolderName = folderParent != 0 ? folderParent->name() : folderParentDir->name();
01858 if ( noneFound ) {
01859
01860 msg = i18n("KMail will now create the required groupware folders"
01861 " as subfolders of %1; if you do not want this, cancel"
01862 " and the IMAP resource will be disabled").arg(parentFolderName);
01863 } else {
01864
01865 QString operations = "<ul>";
01866 for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01867 if ( i != KMail::ContentsTypeMail ) {
01868 QString typeName = localizedDefaultFolderName( static_cast<KMail::FolderContentsType>( i ) );
01869 if ( results[i].found == StandardFolderSearchResult::NotFound )
01870 operations += "<li>" + i18n( "%1: no folder found. It will be created." ).arg( typeName ) + "</li>";
01871 else if ( results[i].found == StandardFolderSearchResult::FoundByType || results[i].found == StandardFolderSearchResult::FoundByName )
01872 operations += "<li>" + i18n( "%1: found folder %2. It will be set as the main groupware folder." ).
01873 arg( typeName ).arg( results[i].folder->label() ) + "</li>";
01874 }
01875 }
01876 operations += "</ul>";
01877
01878 msg = i18n("<qt>KMail found the following groupware folders in %1 and needs to perform the following operations: %2"
01879 "<br>If you do not want this, cancel"
01880 " and the IMAP resource will be disabled").arg(parentFolderName, operations);
01881
01882 }
01883
01884 if( KMessageBox::questionYesNo( 0, msg,
01885 i18n("Standard Groupware Folders"), KStdGuiItem::cont(), KStdGuiItem::cancel() ) == KMessageBox::No ) {
01886
01887 GlobalSettings::self()->setTheIMAPResourceEnabled( false );
01888 mUseResourceIMAP = false;
01889 mFolderParentDir = 0;
01890 mFolderParent = 0;
01891 reloadFolderTree();
01892 return;
01893 }
01894 }
01895
01896
01897 mUseResourceIMAP = true;
01898 mFolderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
01899 if( mFolderLanguage > 3 ) mFolderLanguage = 0;
01900 mFolderParentDir = folderParentDir;
01901 mFolderParent = folderParent;
01902 mFolderType = folderType;
01903 mHideFolders = hideFolders;
01904
01905
01906 cleanup();
01907
01908
01909 mCalendar = initFolder( KMail::ContentsTypeCalendar );
01910 mTasks = initFolder( KMail::ContentsTypeTask );
01911 mJournals = initFolder( KMail::ContentsTypeJournal );
01912 mContacts = initFolder( KMail::ContentsTypeContact );
01913 mNotes = initFolder( KMail::ContentsTypeNote );
01914
01915
01916 if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01917 static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01918 if ( mTasks->folderType() == KMFolderTypeCachedImap )
01919 static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01920 if ( mJournals->folderType() == KMFolderTypeCachedImap )
01921 static_cast<KMFolderCachedImap *>( mJournals->storage() )->updateAnnotationFolderType();
01922 if ( mContacts->folderType() == KMFolderTypeCachedImap )
01923 static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01924 if ( mNotes->folderType() == KMFolderTypeCachedImap )
01925 static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01926
01927
01928
01929
01930
01931
01932 QStringList folderNames;
01933 QValueList<QGuardedPtr<KMFolder> > folderList;
01934 createFolderList( folderNames, folderList );
01935 for( QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
01936 it != folderList.end(); ++it )
01937 {
01938 FolderStorage *storage = (*it)->storage();
01939 KMFolderCachedImap* dimapStorage = dynamic_cast<KMFolderCachedImap*>( storage );
01940 if ( storage && storage->contentsType() != 0 ) {
01941 if ( dimapStorage )
01942 dimapStorage->updateAnnotationFolderType();
01943 folderContentsTypeChanged( *it, storage->contentsType() );
01944 }
01945 }
01946
01947
01948
01949 mExtraFolders.remove( mCalendar->location() );
01950 mExtraFolders.remove( mTasks->location() );
01951 mExtraFolders.remove( mJournals->location() );
01952 mExtraFolders.remove( mContacts->location() );
01953 mExtraFolders.remove( mNotes->location() );
01954
01955 subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
01956 subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
01957 subresourceAdded( folderContentsType( KMail::ContentsTypeJournal ), mJournals->location(), mJournals->label(), true, false );
01958 subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
01959 subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
01960 } else if ( groupwareType == KMAcctCachedImap::GroupwareScalix ) {
01961
01962 mUseResourceIMAP = true;
01963 mFolderParentDir = folderParentDir;
01964 mFolderParent = folderParent;
01965 mFolderType = folderType;
01966 mHideFolders = false;
01967
01968
01969 cleanup();
01970
01971
01972 mCalendar = initScalixFolder( KMail::ContentsTypeCalendar );
01973 mTasks = initScalixFolder( KMail::ContentsTypeTask );
01974 mJournals = 0;
01975 mContacts = initScalixFolder( KMail::ContentsTypeContact );
01976 mNotes = initScalixFolder( KMail::ContentsTypeNote );
01977
01978
01979 if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01980 static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01981 if ( mTasks->folderType() == KMFolderTypeCachedImap )
01982 static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01983 if ( mContacts->folderType() == KMFolderTypeCachedImap )
01984 static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01985 if ( mNotes->folderType() == KMFolderTypeCachedImap )
01986 static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01987
01988
01989
01990
01991 kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
01992 kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
01993 kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
01994
01995
01996 QStringList folderNames;
01997 QValueList<QGuardedPtr<KMFolder> > folderList;
01998 kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
01999 QValueList<QGuardedPtr<KMFolder> >::iterator it;
02000 for(it = folderList.begin(); it != folderList.end(); ++it)
02001 {
02002 FolderStorage *storage = (*it)->storage();
02003
02004 if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
02005 KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
02006
02007 const QString attributes = imapFolder->folderAttributes();
02008 if ( attributes.contains( "X-FolderClass" ) ) {
02009 if ( !attributes.contains( "X-SpecialFolder" ) || (*it)->location().contains( "@" ) ) {
02010 const Scalix::FolderAttributeParser parser( attributes );
02011 if ( !parser.folderClass().isEmpty() ) {
02012 FolderContentsType type = Scalix::Utils::scalixIdToContentsType( parser.folderClass() );
02013 imapFolder->setContentsType( type );
02014 folderContentsTypeChanged( *it, type );
02015 }
02016 }
02017 }
02018 }
02019 }
02020
02021
02022
02023 mExtraFolders.remove( mCalendar->location() );
02024 mExtraFolders.remove( mTasks->location() );
02025 mExtraFolders.remove( mContacts->location() );
02026 mExtraFolders.remove( mNotes->location() );
02027
02028
02029
02030 subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
02031 subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
02032 subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
02033 subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
02034 }
02035
02036 KConfig *config = kmkernel->config();
02037 config->setGroup("Resource UINames");
02038 *KMailICalIfaceImpl::mSubResourceUINamesMap = config->entryMap( "Resource UINames" );
02039
02040 reloadFolderTree();
02041 }
02042
02043 void KMailICalIfaceImpl::slotCheckDone()
02044 {
02045 QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
02046 KMFolder* folderParent = kmkernel->findFolderById( parentName );
02047
02048 if ( folderParent )
02049 {
02050 KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
02051 if ( account )
02052 disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
02053 this, SLOT( slotCheckDone() ) );
02054 readConfig();
02055 }
02056 }
02057
02058 KMFolder* KMailICalIfaceImpl::initFolder( KMail::FolderContentsType contentsType )
02059 {
02060
02061 KMFolderType type = mFolderType;
02062 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02063
02064 KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
02065
02066
02067
02068 StandardFolderSearchResult result = findStandardResourceFolder( mFolderParentDir, contentsType );
02069
02070
02071 if ( result.folders.count() > 1 && result.found == StandardFolderSearchResult::FoundAndStandard ) {
02072 QStringList labels;
02073 for ( QValueList<KMFolder*>::ConstIterator it = result.folders.begin(); it != result.folders.end(); ++it )
02074 labels << (*it)->prettyURL();
02075 const QString selected = KInputDialog::getItem( i18n("Default folder"),
02076 i18n("There are multiple %1 default folders, please choose one:")
02077 .arg( localizedDefaultFolderName( contentsType ) ), labels );
02078 if ( !selected.isEmpty() )
02079 result.folder = result.folders[ labels.findIndex( selected ) ];
02080 }
02081
02082 KMFolder* folder = result.folder;
02083
02084 if ( !folder ) {
02085
02086 folder =
02087 mFolderParentDir->createFolder( localizedDefaultFolderName( contentsType ), false, type );
02088 if( mFolderType == KMFolderTypeImap ) {
02089 KMFolderImap* parentFolder = static_cast<KMFolderImap*>( mFolderParent->storage() );
02090 parentFolder->createFolder( localizedDefaultFolderName( contentsType ) );
02091 static_cast<KMFolderImap*>( folder->storage() )->setAccount( parentFolder->account() );
02092 }
02093
02094 setStorageFormat( folder, globalStorageFormat() );
02095 } else {
02096 FolderInfo info = readFolderInfo( folder );
02097 mFolderInfoMap.insert( folder, info );
02098
02099 }
02100
02101 if( folder->canAccess() != 0 ) {
02102 KMessageBox::sorry(0, i18n("You do not have read/write permission to your %1 folder.")
02103 .arg( folderName( itemType ) ) );
02104 return 0;
02105 }
02106 folder->storage()->setContentsType( contentsType );
02107 folder->setSystemFolder( true );
02108 folder->storage()->writeConfig();
02109 folder->open("ifacefolder");
02110 connectFolder( folder );
02111 return folder;
02112 }
02113
02114 KMFolder* KMailICalIfaceImpl::initScalixFolder( KMail::FolderContentsType contentsType )
02115 {
02116
02117 KMFolderType type = mFolderType;
02118 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02119
02120 KMFolder* folder = 0;
02121
02122
02123 QStringList folderNames;
02124 QValueList<QGuardedPtr<KMFolder> > folderList;
02125 Q_ASSERT( kmkernel );
02126 Q_ASSERT( kmkernel->dimapFolderMgr() );
02127 kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
02128 QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
02129 for(; it != folderList.end(); ++it)
02130 {
02131 FolderStorage *storage = (*it)->storage();
02132
02133 if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
02134 KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
02135
02136 const QString attributes = imapFolder->folderAttributes();
02137 if ( attributes.contains( "X-SpecialFolder" ) ) {
02138 const Scalix::FolderAttributeParser parser( attributes );
02139 if ( contentsType == Scalix::Utils::scalixIdToContentsType( parser.folderClass() ) ) {
02140 folder = *it;
02141 break;
02142 }
02143 }
02144 }
02145 }
02146
02147 if ( !folder ) {
02148 return 0;
02149 } else {
02150 FolderInfo info = readFolderInfo( folder );
02151 mFolderInfoMap.insert( folder, info );
02152
02153 }
02154
02155 if( folder->canAccess() != 0 ) {
02156 KMessageBox::sorry(0, i18n("You do not have read/write permission to your folder.") );
02157 return 0;
02158 }
02159 folder->storage()->setContentsType( contentsType );
02160 folder->setSystemFolder( true );
02161 folder->storage()->writeConfig();
02162 folder->open( "scalixfolder" );
02163 connectFolder( folder );
02164 return folder;
02165 }
02166
02167 void KMailICalIfaceImpl::connectFolder( KMFolder* folder )
02168 {
02169
02170 disconnect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
02171 this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
02172 disconnect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
02173 this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
02174 disconnect( folder, SIGNAL( expunged( KMFolder* ) ),
02175 this, SLOT( slotRefreshFolder( KMFolder* ) ) );
02176 disconnect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
02177 this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
02178 disconnect( folder, SIGNAL( nameChanged() ),
02179 this, SLOT( slotFolderRenamed() ) );
02180 disconnect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
02181 this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
02182
02183
02184 connect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
02185 this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
02186 connect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
02187 this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
02188 connect( folder, SIGNAL( expunged( KMFolder* ) ),
02189 this, SLOT( slotRefreshFolder( KMFolder* ) ) );
02190 connect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
02191 this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
02192 connect( folder, SIGNAL( nameChanged() ),
02193 this, SLOT( slotFolderRenamed() ) );
02194 connect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
02195 this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
02196
02197 }
02198
02199 static void cleanupFolder( KMFolder* folder, KMailICalIfaceImpl* _this )
02200 {
02201 if( folder ) {
02202 folder->setSystemFolder( false );
02203 folder->disconnect( _this );
02204 folder->close("ifacefolder");
02205 }
02206 }
02207
02208 void KMailICalIfaceImpl::cleanup()
02209 {
02210 cleanupFolder( mContacts, this );
02211 cleanupFolder( mCalendar, this );
02212 cleanupFolder( mNotes, this );
02213 cleanupFolder( mTasks, this );
02214 cleanupFolder( mJournals, this );
02215
02216 mContacts = mCalendar = mNotes = mTasks = mJournals = 0;
02217 }
02218
02219 QString KMailICalIfaceImpl::folderPixmap( KFolderTreeItem::Type type ) const
02220 {
02221 if( !mUseResourceIMAP )
02222 return QString::null;
02223
02224 if( type == KFolderTreeItem::Contacts )
02225 return QString::fromLatin1( "kmgroupware_folder_contacts" );
02226 else if( type == KFolderTreeItem::Calendar )
02227 return QString::fromLatin1( "kmgroupware_folder_calendar" );
02228 else if( type == KFolderTreeItem::Notes )
02229 return QString::fromLatin1( "kmgroupware_folder_notes" );
02230 else if( type == KFolderTreeItem::Tasks )
02231 return QString::fromLatin1( "kmgroupware_folder_tasks" );
02232 else if( type == KFolderTreeItem::Journals )
02233 return QString::fromLatin1( "kmgroupware_folder_journals" );
02234
02235 return QString::null;
02236 }
02237
02238 static void reloadFolderTree()
02239 {
02240
02241 kmkernel->folderMgr()->contentsChanged();
02242 }
02243
02244
02245
02246
02247 static void vPartMicroParser( const QString& str, QString& s )
02248 {
02249 QString line;
02250 uint len = str.length();
02251
02252 for( uint i=0; i<len; ++i){
02253 if( str[i] == '\r' || str[i] == '\n' ){
02254 if( str[i] == '\r' )
02255 ++i;
02256 if( i+1 < len && str[i+1] == ' ' ){
02257
02258 ++i;
02259 }else{
02260
02261 if( line.startsWith( s ) ) {
02262 s = line.mid( s.length() + 1 );
02263 return;
02264 }
02265 line = "";
02266 }
02267 } else {
02268 line += str[i];
02269 }
02270 }
02271
02272
02273 s.truncate(0);
02274 }
02275
02276
02277 static QValueList<KMFolder*> findFolderByAnnotation( KMFolderDir* folderParentDir, const QString& annotation )
02278 {
02279 QValueList<KMFolder*> rv;
02280 QPtrListIterator<KMFolderNode> it( *folderParentDir );
02281 for ( ; it.current(); ++it ) {
02282 if ( !it.current()->isDir() ) {
02283 KMFolder* folder = static_cast<KMFolder *>( it.current() );
02284 if ( folder->folderType() == KMFolderTypeCachedImap ) {
02285 QString folderAnnotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
02286
02287 if ( folderAnnotation == annotation )
02288 rv.append( folder );
02289 }
02290 }
02291 }
02292 return rv;
02293 }
02294
02295 KMailICalIfaceImpl::StandardFolderSearchResult KMailICalIfaceImpl::findStandardResourceFolder( KMFolderDir* folderParentDir, KMail::FolderContentsType contentsType )
02296 {
02297 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
02298 {
02299
02300 QValueList<KMFolder*> folders = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) + ".default" );
02301 if ( !folders.isEmpty() )
02302 return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundAndStandard );
02303
02304
02305 folders = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) );
02306 if ( !folders.isEmpty() )
02307 return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundByType );
02308
02309
02310 KMFolderNode* node = folderParentDir->hasNamedFolder( localizedDefaultFolderName( contentsType ) );
02311 if ( node && !node->isDir() )
02312 return StandardFolderSearchResult( static_cast<KMFolder *>( node ), StandardFolderSearchResult::FoundByName );
02313
02314 kdDebug(5006) << "findStandardResourceFolder: found no resource folder for " << s_folderContentsType[contentsType].annotation << endl;
02315 return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02316 }
02317 else
02318 {
02319 KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
02320 unsigned int folderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
02321 if( folderLanguage > 3 ) folderLanguage = 0;
02322 KMFolderNode* node = folderParentDir->hasNamedFolder( folderName( itemType, folderLanguage ) );
02323 if ( !node || node->isDir() )
02324 return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02325 return StandardFolderSearchResult( static_cast<KMFolder*>( node ), StandardFolderSearchResult::FoundAndStandard );
02326 }
02327 }
02328
02329
02330
02331
02332
02333 bool KMailICalIfaceImpl::folderIsAlarmRelevant( const KMFolder *folder )
02334 {
02335 bool administerRights = true;
02336 bool relevantForOwner = true;
02337 bool relevantForEveryone = false;
02338 if ( folder->folderType() == KMFolderTypeImap ) {
02339 const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
02340 administerRights =
02341 imapFolder->userRightsState() != KMail::ACLJobs::Ok ||
02342 imapFolder->userRights() & KMail::ACLJobs::Administer;
02343 }
02344 if ( folder->folderType() == KMFolderTypeCachedImap ) {
02345 const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
02346 administerRights =
02347 dimapFolder->userRightsState() != KMail::ACLJobs::Ok ||
02348 dimapFolder->userRights() & KMail::ACLJobs::Administer;
02349 relevantForOwner = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor () == KMFolderCachedImap::IncForAdmins );
02350 relevantForEveryone = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor() == KMFolderCachedImap::IncForReaders );
02351 }
02352 #if 0
02353 kdDebug(5006) << k_funcinfo << endl;
02354 kdDebug(5006) << "Folder: " << folder->label() << " has administer rights: " << administerRights << endl;
02355 kdDebug(5006) << "and is relevant for owner: " << relevantForOwner << endl;
02356 kdDebug(5006) << "and relevant for everyone: " << relevantForEveryone << endl;
02357 #endif
02358 return ( administerRights && relevantForOwner ) || relevantForEveryone;
02359 }
02360
02361 void KMailICalIfaceImpl::setResourceQuiet(bool q)
02362 {
02363
02364 mResourceQuiet = q;
02365 }
02366
02367 bool KMailICalIfaceImpl::isResourceQuiet() const
02368 {
02369 return mResourceQuiet;
02370 }
02371
02372
02373 bool KMailICalIfaceImpl::addSubresource( const QString& resource,
02374 const QString& parent,
02375 const QString& contentsType )
02376 {
02377 kdDebug(5006) << "Adding subresource to parent: " << parent << " with name: " << resource << endl;
02378 kdDebug(5006) << "contents type: " << contentsType << endl;
02379 KMFolder *folder = findResourceFolder( parent );
02380 KMFolderDir *parentFolderDir = !parent.isEmpty() && folder ? folder->createChildFolder(): mFolderParentDir;
02381 if ( !parentFolderDir || parentFolderDir->hasNamedFolder( resource ) ) return false;
02382
02383 QString msg;
02384 if ( parentFolderDir->owner() && !parentFolderDir->owner()->isValidName( resource, msg ) ) {
02385 KMessageBox::error( 0, msg );
02386 return false;
02387 }
02388
02389 KMFolderType type = mFolderType;
02390 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02391
02392 KMFolder* newFolder = parentFolderDir->createFolder( resource, false, type );
02393 if ( !newFolder ) return false;
02394 if( mFolderType == KMFolderTypeImap )
02395 static_cast<KMFolderImap*>( folder->storage() )->createFolder( resource );
02396
02397 StorageFormat defaultFormat = GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
02398 setStorageFormat( newFolder, folder ? storageFormat( folder ) : defaultFormat );
02399 newFolder->storage()->setContentsType( folderContentsType( contentsType ) );
02400 newFolder->storage()->writeConfig();
02401 newFolder->open( "ical_subresource" );
02402 connectFolder( newFolder );
02403 reloadFolderTree();
02404
02405 return true;
02406 }
02407
02408 bool KMailICalIfaceImpl::removeSubresource( const QString& location )
02409 {
02410 kdDebug(5006) << k_funcinfo << endl;
02411
02412 KMFolder *folder = findResourceFolder( location );
02413
02414
02415
02416
02417 if ( !folder || isStandardResourceFolder( folder ) )
02418 return false;
02419
02420
02421
02422 subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), location );
02423 mExtraFolders.remove( location );
02424 folder->disconnect( this );
02425
02426 if ( folder->folderType() == KMFolderTypeImap )
02427 kmkernel->imapFolderMgr()->remove( folder );
02428 else if ( folder->folderType() == KMFolderTypeCachedImap ) {
02429
02430 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( folder->storage() );
02431 KMAcctCachedImap* acct = storage->account();
02432 if ( acct )
02433 acct->addDeletedFolder( folder );
02434 kmkernel->dimapFolderMgr()->remove( folder );
02435 }
02436 return true;
02437 }
02438
02439 void KMailICalIfaceImpl::syncFolder(KMFolder * folder) const
02440 {
02441 if ( kmkernel->isOffline() || !GlobalSettings::immediatlySyncDIMAPOnGroupwareChanges() )
02442 return;
02443 KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
02444 if ( !dimapFolder )
02445 return;
02446
02447 if ( dimapFolder->imapPath().isEmpty() ) {
02448 if ( folder->parent() && folder->parent()->owner() )
02449 syncFolder( folder->parent()->owner() );
02450 else
02451 return;
02452 }
02453 dimapFolder->account()->processNewMailInFolder( folder );
02454 }
02455
02456 KMailICalIface::Answer KMailICalIfaceImpl::messageReadyForUpdate( const QString &resource,
02457 Q_UINT32 sernum )
02458 {
02459 if ( sernum == 0 ) {
02460
02461 return Yes;
02462 }
02463
02464 KMFolder *folder = findResourceFolder( resource );
02465 if( !folder ) {
02466 kdError(5006) << "update(" << resource << ") : Not an IMAP resource folder" << endl;
02467 return Error;
02468 }
02469
02470 folder->open( "messageReadyForUpdate" );
02471
02472 const KMMessage *msg = findMessageBySerNum( sernum, folder );
02473
02474 if ( !msg ) {
02475 return Error;
02476 }
02477
02478 KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
02479 Answer answer = Yes;
02480 if ( dimapFolder ) {
02481 if ( msg->transferInProgress() || !dimapFolder->isInInitialState() ) {
02482 answer = No;
02483 }
02484 }
02485
02486 folder->close( "messageReadyForUpdate" );
02487 return answer;
02488 }
02489
02490 #include "kmailicalifaceimpl.moc"