kmail

kmailicalifaceimpl.cpp

00001 /*
00002     This file is part of KMail.
00003 
00004     Copyright (c) 2003 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
00005     Copyright (c) 2003 - 2004 Bo Thorsen <bo@sonofthor.dk>
00006     Copyright (c) 2004 Till Adam <adam@kde.org>
00007 
00008     This library is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU Library General Public
00010     License as published by the Free Software Foundation; either
00011     version 2 of the License, or (at your option) any later version.
00012 
00013     This library is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016     Library General Public License for more details.
00017 
00018     You should have received a copy of the GNU Library General Public License
00019     along with this library; see the file COPYING.LIB.  If not, write to
00020     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021     Boston, MA 02110-1301, USA.
00022 
00023     In addition, as a special exception, the copyright holders give
00024     permission to link the code of this program with any edition of
00025     the Qt library by Trolltech AS, Norway (or with modified versions
00026     of Qt that use the same license as Qt), and distribute linked
00027     combinations including the two.  You must obey the GNU General
00028     Public License in all respects for all of the code used other than
00029     Qt.  If you modify this file, you may extend this exception to
00030     your version of the file, but you are not obligated to do so.  If
00031     you do not wish to do so, delete this exception statement from
00032     your version.
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 <dcopclient.h>
00071 #include <kmessagebox.h>
00072 #include <kconfig.h>
00073 #include <kurl.h>
00074 #include <ktempfile.h>
00075 
00076 using namespace KMail;
00077 
00078 // Local helper methods
00079 static void vPartMicroParser( const QString& str, QString& s );
00080 static void reloadFolderTree();
00081 
00082 // The index in this array is the KMail::FolderContentsType enum
00083 static const struct {
00084   const char* contentsTypeStr; // the string used in the DCOP interface
00085   const char* mimetype;
00086   KFolderTreeItem::Type treeItemType;
00087   const char* annotation;
00088   const char* translatedName;
00089 } s_folderContentsType[] = {
00090   { "Mail", "application/x-vnd.kolab.mail", KFolderTreeItem::Other, "mail", I18N_NOOP( "Mail" ) },
00091   { "Calendar", "application/x-vnd.kolab.event", KFolderTreeItem::Calendar, "event", I18N_NOOP( "Calendar" ) },
00092   { "Contact", "application/x-vnd.kolab.contact", KFolderTreeItem::Contacts, "contact", I18N_NOOP( "Contacts" ) },
00093   { "Note", "application/x-vnd.kolab.note", KFolderTreeItem::Notes, "note", I18N_NOOP( "Notes" ) },
00094   { "Task", "application/x-vnd.kolab.task", KFolderTreeItem::Tasks, "task", I18N_NOOP( "Tasks" ) },
00095   { "Journal", "application/x-vnd.kolab.journal", KFolderTreeItem::Journals, "journal", I18N_NOOP( "Journal" ) }
00096 };
00097 
00098 static QString folderContentsType( KMail::FolderContentsType type )
00099 {
00100   return s_folderContentsType[type].contentsTypeStr;
00101 }
00102 
00103 static QString folderKolabMimeType( KMail::FolderContentsType type )
00104 {
00105   return s_folderContentsType[type].mimetype;
00106 }
00107 
00108 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::globalStorageFormat() const {
00109   return GlobalSettings::self()->theIMAPResourceStorageFormat()
00110     == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
00111 }
00112 
00113 static KMail::FolderContentsType folderContentsType( const QString& type )
00114 {
00115   for ( uint i = 0 ; i < sizeof s_folderContentsType / sizeof *s_folderContentsType; ++i )
00116     if ( type == s_folderContentsType[i].contentsTypeStr )
00117       return static_cast<KMail::FolderContentsType>( i );
00118   return KMail::ContentsTypeMail;
00119 }
00120 
00121 static QString localizedDefaultFolderName( KMail::FolderContentsType type )
00122 {
00123   return i18n( s_folderContentsType[type].translatedName );
00124 }
00125 
00126 const char* KMailICalIfaceImpl::annotationForContentsType( KMail::FolderContentsType type )
00127 {
00128   return s_folderContentsType[type].annotation;
00129 }
00130 
00131 ExtraFolder::ExtraFolder( KMFolder* f )
00132     : folder( f )
00133 {
00134     folder->open("kmailicaliface::extrafolder");
00135 }
00136 
00137 ExtraFolder::~ExtraFolder()
00138 {
00139     if ( folder )
00140         folder->close("kmailicaliface::extrafolder");
00141 }
00142 
00143 
00144 /*
00145   This interface has three parts to it - libkcal interface;
00146   kmail interface; and helper functions.
00147 
00148   The libkcal interface and the kmail interface have the same three
00149   methods: add, delete and refresh. The only difference is that the
00150   libkcal interface is used from the IMAP resource in libkcal and
00151   the kmail interface is used from the groupware object in kmail.
00152 */
00153 
00154 KMailICalIfaceImpl::KMailICalIfaceImpl()
00155   : DCOPObject( "KMailICalIface" ), QObject( 0, "KMailICalIfaceImpl" ),
00156     mContacts( 0 ), mCalendar( 0 ), mNotes( 0 ), mTasks( 0 ), mJournals( 0 ),
00157     mFolderLanguage( 0 ), mFolderParentDir( 0 ), mFolderType( KMFolderTypeUnknown ),
00158     mUseResourceIMAP( false ), mResourceQuiet( false ), mHideFolders( true )
00159 {
00160   // Listen to config changes
00161   connect( kmkernel, SIGNAL( configChanged() ), this, SLOT( readConfig() ) );
00162   connect( kmkernel, SIGNAL( folderRemoved( KMFolder* ) ),
00163            this, SLOT( slotFolderRemoved( KMFolder* ) ) );
00164 
00165   mExtraFolders.setAutoDelete( true );
00166   mAccumulators.setAutoDelete( true );
00167 }
00168 
00169 
00170 /* libkcal part of the interface, called from the resources using this
00171  * when incidences are added or deleted */
00172 
00173 // Helper function to find an attachment of a given mimetype
00174 // Can't use KMMessage::findDwBodyPart since it only works with known mimetypes.
00175 static DwBodyPart* findBodyPartByMimeType( const KMMessage& msg, const char* sType, const char* sSubtype, bool startsWith = false )
00176 {
00177   // quickly searching for our message part: since Kolab parts are
00178   // top-level parts we do *not* have to travel into embedded multiparts
00179   DwBodyPart* part = msg.getFirstDwBodyPart();
00180   while( part ){
00181   //    kdDebug() << part->Headers().ContentType().TypeStr().c_str() << " "
00182   //            << part->Headers().ContentType().SubtypeStr().c_str() << endl;
00183     if ( part->hasHeaders() ) {
00184       DwMediaType& contentType = part->Headers().ContentType();
00185       if ( startsWith ) {
00186         if ( contentType.TypeStr() == sType
00187              && QString( contentType.SubtypeStr().c_str() ).startsWith( sSubtype ) )
00188           return part;
00189       }
00190       else
00191         if ( contentType.TypeStr() == sType
00192              && contentType.SubtypeStr() == sSubtype )
00193           return part;
00194     }
00195     part = part->Next();
00196   }
00197   return 0;
00198 }
00199 
00200 // Helper function to find an attachment with a given filename
00201 static DwBodyPart* findBodyPart( const KMMessage& msg, const QString& attachmentName )
00202 {
00203   // quickly searching for our message part: since Kolab parts are
00204   // top-level parts we do *not* have to travel into embedded multiparts
00205   for ( DwBodyPart* part = msg.getFirstDwBodyPart(); part; part = part->Next() ) {
00206     //kdDebug(5006) << "findBodyPart:  - " << part->Headers().ContentDisposition().Filename().c_str() << endl;
00207     if ( part->hasHeaders()
00208          && attachmentName == part->Headers().ContentDisposition().Filename().c_str() )
00209       return part;
00210     if ( part->hasHeaders() && attachmentName == part->Headers().ContentType().Name().c_str() )
00211       return part;
00212   }
00213   return 0;
00214 }
00215 
00216 #if 0
00217 static void debugBodyParts( const char* foo, const KMMessage& msg )
00218 {
00219   kdDebug(5006) << "--debugBodyParts " << foo << "--" << endl;
00220   for ( DwBodyPart* part = msg.getFirstDwBodyPart(); part; part = part->Next() ) {
00221     if ( part->hasHeaders() ) {
00222       kdDebug(5006) << " bodypart: " << part << endl;
00223       kdDebug(5006) << "        " << part->Headers().AsString().c_str() << endl;
00224     }
00225     else
00226       kdDebug(5006) << " part " << part << " has no headers" << endl;
00227   }
00228 }
00229 #else
00230 inline static void debugBodyParts( const char*, const KMMessage& ) {}
00231 #endif
00232 
00233 
00234 // Add (or overwrite, resp.) an attachment in an existing mail,
00235 // attachments must be local files, they are identified by their names.
00236 // If lookupByName if false the attachment to replace is looked up by mimetype.
00237 // return value: wrong if attachment could not be added/updated
00238 bool KMailICalIfaceImpl::updateAttachment( KMMessage& msg,
00239                                            const QString& attachmentURL,
00240                                            const QString& attachmentName,
00241                                            const QString& attachmentMimetype,
00242                                            bool lookupByName )
00243 {
00244   kdDebug(5006) << "KMailICalIfaceImpl::updateAttachment( " << attachmentURL << " )" << endl;
00245 
00246   bool bOK = false;
00247 
00248   KURL url( attachmentURL );
00249   if ( url.isValid() && url.isLocalFile() ) {
00250     const QString fileName( url.path() );
00251     QFile file( fileName );
00252     if( file.open( IO_ReadOnly ) ) {
00253       QByteArray rawData = file.readAll();
00254       file.close();
00255 
00256       // create the new message part with data read from temp file
00257       KMMessagePart msgPart;
00258       msgPart.setName( attachmentName );
00259 
00260       const int iSlash = attachmentMimetype.find('/');
00261       const QCString sType    = attachmentMimetype.left( iSlash   ).latin1();
00262       const QCString sSubtype = attachmentMimetype.mid(  iSlash+1 ).latin1();
00263       msgPart.setTypeStr( sType );
00264       msgPart.setSubtypeStr( sSubtype );
00265       QCString ctd("attachment;\n  filename=\"");
00266       ctd.append( attachmentName.latin1() );
00267       ctd.append("\"");
00268       msgPart.setContentDisposition( ctd );
00269       QValueList<int> dummy;
00270       msgPart.setBodyAndGuessCte( rawData, dummy );
00271       msgPart.setPartSpecifier( fileName );
00272 
00273       DwBodyPart* newPart = msg.createDWBodyPart( &msgPart );
00274       // This whole method is a bit special. We mix code for writing and code for reading.
00275       // E.g. we need to parse the content-disposition again for ContentDisposition().Filename()
00276       // to work later on.
00277       newPart->Headers().ContentDisposition().Parse();
00278 
00279       DwBodyPart* part = lookupByName ? findBodyPart( msg, attachmentName )
00280                          : findBodyPartByMimeType( msg, sType, sSubtype );
00281       if ( part ) {
00282         // Make sure the replacing body part is pointing
00283         // to the same next part as the original body part.
00284         newPart->SetNext( part->Next() );
00285         // call DwBodyPart::operator =
00286         // which calls DwEntity::operator =
00287         *part = *newPart;
00288         delete newPart;
00289         msg.setNeedsAssembly();
00290         kdDebug(5006) << "Attachment " << attachmentName << " updated." << endl;
00291       } else {
00292         msg.addDwBodyPart( newPart );
00293         kdDebug(5006) << "Attachment " << attachmentName << " added." << endl;
00294       }
00295       bOK = true;
00296     }else{
00297       kdDebug(5006) << "Attachment " << attachmentURL << " can not be read." << endl;
00298     }
00299   }else{
00300     kdDebug(5006) << "Attachment " << attachmentURL << " not a local file." << endl;
00301   }
00302 
00303   return bOK;
00304 }
00305 
00306 // Look for the attachment with the right mimetype
00307 bool KMailICalIfaceImpl::kolabXMLFoundAndDecoded( const KMMessage& msg, const QString& mimetype, QString& s )
00308 {
00309   const int iSlash = mimetype.find('/');
00310   const QCString sType    = mimetype.left( iSlash   ).latin1();
00311   const QCString sSubtype = mimetype.mid(  iSlash+1 ).latin1();
00312   DwBodyPart* part = findBodyPartByMimeType( msg, sType, sSubtype, true /* starts with sSubtype, to accept application/x-vnd.kolab.contact.distlist */ );
00313   if ( part ) {
00314     KMMessagePart msgPart;
00315     KMMessage::bodyPart(part, &msgPart);
00316     s = msgPart.bodyToUnicode( QTextCodec::codecForName( "utf8" ) );
00317     return true;
00318   }
00319   return false;
00320 }
00321 
00322 // Delete an attachment in an existing mail.
00323 // return value: wrong if attachment could not be deleted
00324 //
00325 // This code could be optimized: for now we just replace
00326 // the attachment by an empty dummy attachment since Mimelib
00327 // does not provide an option for deleting attachments yet.
00328 bool KMailICalIfaceImpl::deleteAttachment( KMMessage& msg,
00329                                            const QString& attachmentName )
00330 {
00331   kdDebug(5006) << "KMailICalIfaceImpl::deleteAttachment( " << attachmentName << " )" << endl;
00332 
00333   bool bOK = false;
00334 
00335   // quickly searching for our message part: since Kolab parts are
00336   // top-level parts we do *not* have to travel into embedded multiparts
00337   DwBodyPart* part = findBodyPart( msg, attachmentName );
00338   if ( part ) {
00339     msg.getTopLevelPart()->Body().RemoveBodyPart( part );
00340     delete part;
00341     msg.setNeedsAssembly();
00342     kdDebug(5006) << "Attachment deleted." << endl;
00343     bOK = true;
00344   }
00345 
00346   if( !bOK ){
00347     kdDebug(5006) << "Attachment " << attachmentName << " not found." << endl;
00348   }
00349 
00350   return bOK;
00351 }
00352 
00353 static void setIcalVcardContentTypeHeader( KMMessage *msg, KMail::FolderContentsType t, KMFolder *folder )
00354 {
00355   KMAcctCachedImap::GroupwareType groupwareType = KMAcctCachedImap::GroupwareKolab;
00356 
00357   KMFolderCachedImap *imapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
00358   if ( imapFolder )
00359     groupwareType = imapFolder->account()->groupwareType();
00360 
00361   msg->setType( DwMime::kTypeText );
00362   if ( t == KMail::ContentsTypeCalendar || t == KMail::ContentsTypeTask
00363       || t == KMail::ContentsTypeJournal ) {
00364     msg->setSubtype( DwMime::kSubtypeVCal );
00365 
00366     if ( groupwareType == KMAcctCachedImap::GroupwareKolab )
00367       msg->setHeaderField("Content-Type",
00368           "text/calendar; method=REQUEST; charset=\"utf-8\"");
00369     else if ( groupwareType == KMAcctCachedImap::GroupwareScalix )
00370       msg->setHeaderField("Content-Type",
00371           "text/calendar; method=PUBLISH; charset=\"UTF-8\"");
00372 
00373   } else if ( t == KMail::ContentsTypeContact ) {
00374     msg->setSubtype( DwMime::kSubtypeXVCard );
00375     if ( groupwareType == KMAcctCachedImap::GroupwareKolab )
00376       msg->setHeaderField( "Content-Type", "Text/X-VCard; charset=\"utf-8\"" );
00377     else if ( groupwareType == KMAcctCachedImap::GroupwareScalix )
00378       msg->setHeaderField( "Content-Type", "application/scalix-properties; charset=\"UTF-8\"" );
00379   } else {
00380     kdWarning(5006) << k_funcinfo << "Attempt to write non-groupware contents to folder" << endl;
00381   }
00382 }
00383 
00384 static void setXMLContentTypeHeader( KMMessage *msg, const QString plainTextBody )
00385 {
00386    // add a first body part to be displayed by all mailer
00387     // than can NOT display Kolab data: no matter if these
00388     // mailers are MIME compliant or not
00389     KMMessagePart firstPart;
00390     firstPart.setType( DwMime::kTypeText );
00391     firstPart.setSubtype( DwMime::kSubtypePlain );
00392     msg->removeHeaderField( "Content-Type" );
00393     msg->setType( DwMime::kTypeMultipart );
00394     msg->setSubtype( DwMime::kSubtypeMixed );
00395     msg->headers().ContentType().CreateBoundary( 0 );
00396     msg->headers().ContentType().Assemble();
00397     firstPart.setBodyFromUnicode( plainTextBody );
00398     msg->addBodyPart( &firstPart );
00399 }
00400 
00401 // Store a new entry that was received from the resource
00402 Q_UINT32 KMailICalIfaceImpl::addIncidenceKolab( KMFolder& folder,
00403                                                 const QString& subject,
00404                                                 const QString& plainTextBody,
00405                                                 const QMap<QCString, QString>& customHeaders,
00406                                                 const QStringList& attachmentURLs,
00407                                                 const QStringList& attachmentNames,
00408                                                 const QStringList& attachmentMimetypes )
00409 {
00410   kdDebug(5006) << "KMailICalIfaceImpl::addIncidenceKolab( " << attachmentNames << " )" << endl;
00411 
00412   Q_UINT32 sernum = 0;
00413   bool bAttachOK = true;
00414 
00415   // Make a new message for the incidence
00416   KMMessage* msg = new KMMessage();
00417   msg->initHeader();
00418   msg->setSubject( subject );
00419   msg->setAutomaticFields( true );
00420 
00421   QMap<QCString, QString>::ConstIterator ith = customHeaders.begin();
00422   const QMap<QCString, QString>::ConstIterator ithEnd = customHeaders.end();
00423   for ( ; ith != ithEnd ; ++ith ) {
00424     msg->setHeaderField( ith.key(), ith.data() );
00425   }
00426   // In case of the ical format, simply add the plain text content with the
00427   // right content type
00428   if ( storageFormat( &folder ) == StorageXML ) {
00429     setXMLContentTypeHeader( msg, plainTextBody );
00430   } else if ( storageFormat( &folder ) == StorageIcalVcard ) {
00431     const KMail::FolderContentsType t = folder.storage()->contentsType();
00432     setIcalVcardContentTypeHeader( msg, t, &folder );
00433     msg->setBodyEncoded( plainTextBody.utf8() );
00434   } else {
00435     kdWarning(5006) << k_funcinfo << "Attempt to write to folder with unknown storage type" << endl;
00436   }
00437 
00438   Q_ASSERT( attachmentMimetypes.count() == attachmentURLs.count() );
00439   Q_ASSERT( attachmentNames.count() == attachmentURLs.count() );
00440   // Add all attachments by reading them from their temp. files
00441   QStringList::ConstIterator itmime = attachmentMimetypes.begin();
00442   QStringList::ConstIterator iturl = attachmentURLs.begin();
00443   for( QStringList::ConstIterator itname = attachmentNames.begin();
00444        itname != attachmentNames.end()
00445        && itmime != attachmentMimetypes.end()
00446        && iturl != attachmentURLs.end();
00447        ++itname, ++iturl, ++itmime ){
00448     bool byname = !(*itmime).startsWith( "application/x-vnd.kolab." );
00449     if( !updateAttachment( *msg, *iturl, *itname, *itmime, byname ) ){
00450       kdWarning(5006) << "Attachment error, can not add Incidence." << endl;
00451       bAttachOK = false;
00452       break;
00453     }
00454   }
00455 
00456   if( bAttachOK ){
00457     // Mark the message as read and store it in the folder
00458     msg->cleanupHeader();
00459     //debugBodyParts( "after cleanup", *msg );
00460     msg->touch();
00461     if ( folder.addMsg( msg ) == 0 )
00462       // Message stored
00463       sernum = msg->getMsgSerNum();
00464     kdDebug(5006) << "addIncidenceKolab(): Message done and saved. Sernum: "
00465                   << sernum << endl;
00466 
00467     //debugBodyParts( "after addMsg", *msg );
00468     addFolderChange( &folder, Contents );
00469   } else
00470     kdError(5006) << "addIncidenceKolab(): Message *NOT* saved!\n";
00471 
00472   return sernum;
00473 }
00474 
00475 bool KMailICalIfaceImpl::deleteIncidenceKolab( const QString& resource,
00476                                                Q_UINT32 sernum )
00477 {
00478   // Find the message from the serial number and delete it.
00479   if( !mUseResourceIMAP )
00480     return false;
00481 
00482   kdDebug(5006) << "KMailICalIfaceImpl::deleteIncidenceKolab( "
00483                 << resource << ", " << sernum << ")\n";
00484 
00485   // Find the folder
00486   KMFolder* f = findResourceFolder( resource );
00487   if( !f ) {
00488     kdError(5006) << "deleteIncidenceKolab(" << resource << ") : Not an IMAP resource folder" << endl;
00489     return false;
00490   }
00491 
00492   bool rc = false;
00493 
00494   KMMessage* msg = findMessageBySerNum( sernum, f );
00495   if( msg ) {
00496     // Message found - delete it and return happy
00497     deleteMsg( msg );
00498     rc = true;
00499   } else {
00500     kdDebug(5006) << "Message not found, cannot remove serNum " << sernum << endl;
00501   }
00502   return rc;
00503 }
00504 
00505 
00506 int KMailICalIfaceImpl::incidencesKolabCount( const QString& mimetype,
00507                                               const QString& resource )
00508 {
00509   Q_UNUSED( mimetype ); // honouring that would be too slow...
00510 
00511   if( !mUseResourceIMAP )
00512     return 0;
00513 
00514   KMFolder* f = findResourceFolder( resource );
00515   if( !f ) {
00516     kdError(5006) << "incidencesKolab(" << resource << ") : Not an IMAP resource folder" << endl;
00517     return 0;
00518   }
00519 
00520   f->open("kolabcount");
00521   int n = f->count();
00522   f->close("kolabcount");
00523   kdDebug(5006) << "KMailICalIfaceImpl::incidencesKolabCount( "
00524                 << resource << " ) returned " << n << endl;
00525   return n;
00526 }
00527 
00528 QMap<Q_UINT32, QString> KMailICalIfaceImpl::incidencesKolab( const QString& mimetype,
00529                                                              const QString& resource,
00530                                                              int startIndex,
00531                                                              int nbMessages )
00532 {
00536 
00537   QMap<Q_UINT32, QString> aMap;
00538   if( !mUseResourceIMAP )
00539     return aMap;
00540 
00541   KMFolder* f = findResourceFolder( resource );
00542   if( !f ) {
00543     kdError(5006) << "incidencesKolab(" << resource << ") : Not an IMAP resource folder" << endl;
00544     return aMap;
00545   }
00546 
00547   f->open( "incidences" );
00548 
00549   int stopIndex = nbMessages == -1 ? f->count() :
00550                   QMIN( f->count(), startIndex + nbMessages );
00551   kdDebug(5006) << "KMailICalIfaceImpl::incidencesKolab( " << mimetype << ", "
00552                 << resource << " ) from " << startIndex << " to " << stopIndex << endl;
00553 
00554   for(int i = startIndex; i < stopIndex; ++i) {
00555 #if 0
00556     bool unget = !f->isMessage(i);
00557     KMMessage* msg = f->getMsg( i );
00558 #else // faster
00559     KMMessage* msg = f->storage()->readTemporaryMsg(i);
00560 #endif
00561     if ( msg ) {
00562       const int iSlash = mimetype.find('/');
00563       const QCString sType    = mimetype.left( iSlash   ).latin1();
00564       const QCString sSubtype = mimetype.mid(  iSlash+1 ).latin1();
00565       if ( sType.isEmpty() || sSubtype.isEmpty() ) {
00566         kdError(5006) << mimetype << " not an type/subtype combination" << endl;
00567       } else {
00568         DwBodyPart* dwPart = findBodyPartByMimeType( *msg, sType, sSubtype );
00569         if ( dwPart ) {
00570           KMMessagePart msgPart;
00571           KMMessage::bodyPart(dwPart, &msgPart);
00572           aMap.insert(msg->getMsgSerNum(), msgPart.bodyToUnicode( QTextCodec::codecForName( "utf8" ) ));
00573         } else {
00574           // Check if the whole message has the right types. This is what
00575           // happens in the case of ical storage, where the whole mail is
00576           // the data
00577           const QCString type( msg->typeStr() );
00578           const QCString subtype( msg->subtypeStr() );
00579           if (type.lower() == sType && subtype.lower() == sSubtype ) {
00580             aMap.insert( msg->getMsgSerNum(), msg->bodyToUnicode() );
00581           }
00582           // This is *not* an error: it may be that not all of the messages
00583           // have a message part that is matching the wanted MIME type
00584         }
00585       }
00586 #if 0
00587       if( unget ) f->unGetMsg(i);
00588 #else
00589       delete msg;
00590 #endif
00591     }
00592   }
00593   f->close( "incidences" );
00594   return aMap;
00595 }
00596 
00597 
00598 /* Called when a message that was downloaded from an online imap folder
00599  * arrives. Needed when listing incidences on online account folders. */
00600 // TODO: Till, port me
00601 void KMailICalIfaceImpl::slotMessageRetrieved( KMMessage* msg )
00602 {
00603   if( !msg ) return;
00604 
00605   KMFolder *parent = msg->parent();
00606   Q_ASSERT( parent );
00607   Q_UINT32 sernum = msg->getMsgSerNum();
00608 
00609   // do we have an accumulator for this folder?
00610   Accumulator *ac = mAccumulators.find( parent->location() );
00611   if( ac ) {
00612     QString s;
00613     if ( !vPartFoundAndDecoded( msg, s ) ) return;
00614     QString uid( "UID" );
00615     vPartMicroParser( s, uid );
00616     const Q_UINT32 sernum = msg->getMsgSerNum();
00617     mUIDToSerNum.insert( uid, sernum );
00618     ac->add( s );
00619     if( ac->isFull() ) {
00620       /* if this was the last one we were waiting for, tell the resource
00621        * about the new incidences and clean up. */
00622       //asyncLoadResult( ac->incidences, ac->type, ac->folder );
00623       mAccumulators.remove( ac->folder ); // autodelete
00624     }
00625   } else {
00626     /* We are not accumulating for this folder, so this one was added
00627      * by KMail. Do your thang. */
00628      slotIncidenceAdded( msg->parent(), msg->getMsgSerNum() );
00629   }
00630 
00631   if ( mTheUnGetMes.contains( sernum ) ) {
00632     mTheUnGetMes.remove( sernum );
00633     int i = 0;
00634     KMFolder* folder = 0;
00635     KMMsgDict::instance()->getLocation( sernum, &folder, &i );
00636     folder->unGetMsg( i );
00637   }
00638 }
00639 
00640 static QString subresourceLabelForPresentation( const KMFolder * folder )
00641 {
00642     QString label = folder->prettyURL();
00643     QStringList parts = QStringList::split( QString::fromLatin1("/"), label );
00644     // In the common special case of some other user's folder shared with us
00645     // the url looks like "Server Name/user/$USERNAME/Folder/Name". Make
00646     // those a bit nicer.
00647     if ( parts[1] == QString::fromLatin1("user") ) {
00648         QStringList remainder(parts);
00649         remainder.pop_front();
00650         remainder.pop_front();
00651         remainder.pop_front();
00652         label = i18n("%1's %2")
00653             .arg( parts[2] )
00654             .arg( remainder.join( QString::fromLatin1("/") ) );
00655     }
00656     // Another special case is our own folders, under the imap INBOX, make
00657     // those prettier too
00658     if ( parts[1] == QString::fromLatin1("inbox" ) ) {
00659         QStringList remainder(parts);
00660         remainder.pop_front();
00661         remainder.pop_front();
00662         label = i18n("My %1")
00663             .arg( remainder.join( QString::fromLatin1("/") ) );
00664 
00665     }
00666     return label;
00667 }
00668 
00669 /* list all available subresources */
00670 QValueList<KMailICalIfaceImpl::SubResource> KMailICalIfaceImpl::subresourcesKolab( const QString& contentsType )
00671 {
00672   QValueList<SubResource> subResources;
00673 
00674   // Add the default one
00675   KMFolder* f = folderFromType( contentsType, QString::null );
00676   if ( f ) {
00677     subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
00678                                       !f->isReadOnly(), folderIsAlarmRelevant( f ) ) );
00679     kdDebug(5006) << "Adding(1) folder " << f->location() << "    " <<
00680       ( f->isReadOnly() ? "readonly" : "" ) << endl;
00681   }
00682 
00683   // get the extra ones
00684   const KMail::FolderContentsType t = folderContentsType( contentsType );
00685   QDictIterator<ExtraFolder> it( mExtraFolders );
00686   for ( ; it.current(); ++it ){
00687     f = it.current()->folder;
00688     if ( f && f->storage()->contentsType() == t ) {
00689       subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
00690                                         !f->isReadOnly(), folderIsAlarmRelevant( f ) ) );
00691       kdDebug(5006) << "Adding(2) folder " << f->location() << "     " <<
00692               ( f->isReadOnly() ? "readonly" : "" ) << endl;
00693     }
00694   }
00695 
00696   if ( subResources.isEmpty() )
00697     kdDebug(5006) << "subresourcesKolab: No folder found for " << contentsType << endl;
00698   return subResources;
00699 }
00700 
00701 bool KMailICalIfaceImpl::triggerSync( const QString& contentsType )
00702 {
00703   kdDebug(5006) << k_funcinfo << endl;
00704   QValueList<KMailICalIfaceImpl::SubResource> folderList = subresourcesKolab( contentsType );
00705   for ( QValueList<KMailICalIfaceImpl::SubResource>::const_iterator it( folderList.begin() ),
00706                                                                     end( folderList.end() );
00707         it != end ; ++it ) {
00708     KMFolder * const f = findResourceFolder( (*it).location );
00709     if ( !f ) continue;
00710     if ( f->folderType() == KMFolderTypeImap || f->folderType() == KMFolderTypeCachedImap ) {
00711       if ( !kmkernel->askToGoOnline() ) {
00712         return false;
00713       }
00714     }
00715 
00716     if ( f->folderType() == KMFolderTypeImap ) {
00717       KMFolderImap *imap = static_cast<KMFolderImap*>( f->storage() );
00718       imap->getAndCheckFolder();
00719     } else if ( f->folderType() == KMFolderTypeCachedImap ) {
00720       KMFolderCachedImap* cached = static_cast<KMFolderCachedImap*>( f->storage() );
00721       cached->account()->processNewMailSingleFolder( f );
00722     }
00723   }
00724   return true;
00725 }
00726 
00727 /* Used by the resource to query whether folders are writable. */
00728 bool KMailICalIfaceImpl::isWritableFolder( const QString& type,
00729                                            const QString& resource )
00730 {
00731   KMFolder* f = folderFromType( type, resource );
00732   if ( !f )
00733     // Definitely not writable
00734     return false;
00735 
00736   return !f->isReadOnly();
00737 }
00738 
00739 /* Used by the resource to query the storage format of the folder. */
00740 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( const QString& resource )
00741 {
00742   StorageFormat format;
00743   KMFolder* f = findResourceFolder( resource );
00744   if ( f )
00745     format = storageFormat( f );
00746   else
00747     format = globalStorageFormat();
00748   return format;
00749 }
00750 
00765 Q_UINT32 KMailICalIfaceImpl::update( const QString& resource,
00766                                      Q_UINT32 sernum,
00767                                      const QString& subject,
00768                                      const QString& plainTextBody,
00769                                      const QMap<QCString, QString>& customHeaders,
00770                                      const QStringList& attachmentURLs,
00771                                      const QStringList& attachmentMimetypes,
00772                                      const QStringList& attachmentNames,
00773                                      const QStringList& deletedAttachments )
00774 {
00775   Q_UINT32 rc = 0;
00776 
00777    if( !mUseResourceIMAP )
00778     return rc;
00779 
00780   Q_ASSERT( !resource.isEmpty() );
00781 
00782   kdDebug(5006) << "KMailICalIfaceImpl::update( " << resource << ", " << sernum << " )\n";
00783   kdDebug(5006) << attachmentURLs << "\n";
00784   kdDebug(5006) << attachmentMimetypes << "\n";
00785   kdDebug(5006) << attachmentNames << "\n";
00786   kdDebug(5006) << "deleted attachments:" << deletedAttachments << "\n";
00787 
00788   // Find the folder
00789   KMFolder* f = findResourceFolder( resource );
00790   if( !f ) {
00791     kdError(5006) << "update(" << resource << ") : Not an IMAP resource folder" << endl;
00792     return rc;
00793   }
00794 
00795   f->open( "ifaceupdate" );
00796 
00797   KMMessage* msg = 0;
00798   if ( sernum != 0 ) {
00799     msg = findMessageBySerNum( sernum, f );
00800     if ( !msg ) return 0;
00801     // Message found - make a copy and update it:
00802     KMMessage* newMsg = new KMMessage( *msg );
00803     newMsg->setSubject( subject );
00804     QMap<QCString, QString>::ConstIterator ith = customHeaders.begin();
00805     const QMap<QCString, QString>::ConstIterator ithEnd = customHeaders.begin();
00806     for ( ; ith != ithEnd ; ++ith )
00807       newMsg->setHeaderField( ith.key(), ith.data() );
00808     newMsg->setParent( 0 ); // workaround strange line in KMMsgBase::assign. newMsg is not in any folder yet.
00809     // Note that plainTextBody isn't used in this branch. We assume it's still valid from when the mail was created.
00810 
00811     // Delete some attachments according to list
00812     for( QStringList::ConstIterator it = deletedAttachments.begin();
00813          it != deletedAttachments.end();
00814          ++it ){
00815       if( !deleteAttachment( *newMsg, *it ) ){
00816         // Note: It is _not_ an error if an attachment was already deleted.
00817       }
00818     }
00819 
00820     const KMail::FolderContentsType t = f->storage()->contentsType();
00821     const QCString type = msg->typeStr();
00822     const QCString subtype = msg->subtypeStr();
00823     const bool messageWasIcalVcardFormat = ( type.lower() == "text" &&
00824         ( subtype.lower() == "calendar" || subtype.lower() == "x-vcard" ) );
00825 
00826     if ( storageFormat( f ) == StorageIcalVcard ) {
00827       //kdDebug(5006) << k_funcinfo << " StorageFormatIcalVcard " << endl;
00828       if ( !messageWasIcalVcardFormat ) {
00829         setIcalVcardContentTypeHeader( newMsg, t, f );
00830       }
00831       newMsg->setBodyEncoded( plainTextBody.utf8() );
00832     } else if ( storageFormat( f ) == StorageXML ) {
00833       if ( messageWasIcalVcardFormat ) {
00834         // this was originally an ical event, but the folder changed to xml,
00835         // convert
00836        setXMLContentTypeHeader( newMsg, plainTextBody );
00837       }
00838       //kdDebug(5006) << k_funcinfo << " StorageFormatXML " << endl;
00839       // Add all attachments by reading them from their temp. files
00840       QStringList::ConstIterator iturl = attachmentURLs.begin();
00841       QStringList::ConstIterator itmime = attachmentMimetypes.begin();
00842       QStringList::ConstIterator itname = attachmentNames.begin();
00843       for( ;
00844           iturl != attachmentURLs.end()
00845           && itmime != attachmentMimetypes.end()
00846           && itname != attachmentNames.end();
00847           ++iturl, ++itname, ++itmime ){
00848         bool byname = !(*itmime).startsWith( "application/x-vnd.kolab." );
00849         if( !updateAttachment( *newMsg, *iturl, *itname, *itmime, byname ) ){
00850           kdDebug(5006) << "Attachment error, can not update attachment " << *iturl << endl;
00851           break;
00852         }
00853       }
00854     }
00855 
00856     //debugBodyParts( "in update, before cleanup", *newMsg );
00857 
00858     // This is necessary for the headers to be readable later on
00859     newMsg->cleanupHeader();
00860 
00861     //debugBodyParts( "in update, after cleanup", *newMsg );
00862 
00863     deleteMsg( msg );
00864     if ( f->addMsg( newMsg ) == 0 ) {
00865       // Message stored
00866       rc = newMsg->getMsgSerNum();
00867       kdDebug(5006) << "forget about " << sernum << ", it's " << rc << " now" << endl;
00868     }
00869     addFolderChange( f, Contents );
00870   } else {
00871     // Message not found - store it newly
00872     rc = addIncidenceKolab( *f, subject, plainTextBody, customHeaders,
00873                             attachmentURLs,
00874                             attachmentNames,
00875                             attachmentMimetypes );
00876   }
00877 
00878   f->close("ifaceupdate");
00879   return rc;
00880 }
00881 
00882 KURL KMailICalIfaceImpl::getAttachment( const QString& resource,
00883                                         Q_UINT32 sernum,
00884                                         const QString& filename )
00885 {
00886   // This finds the attachment with the filename, saves it to a
00887   // temp file and returns a URL to it. It's up to the resource
00888   // to delete the tmp file later.
00889   if( !mUseResourceIMAP )
00890     return KURL();
00891 
00892   kdDebug(5006) << "KMailICalIfaceImpl::getAttachment( "
00893                 << resource << ", " << sernum << ", " << filename << " )\n";
00894 
00895   // Find the folder
00896   KMFolder* f = findResourceFolder( resource );
00897   if( !f ) {
00898     kdError(5006) << "getAttachment(" << resource << ") : Not an IMAP resource folder" << endl;
00899     return KURL();
00900   }
00901   if ( storageFormat( f ) != StorageXML ) {
00902     kdError(5006) << "getAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
00903     return KURL();
00904   }
00905 
00906   KURL url;
00907 
00908   bool bOK = false;
00909   bool quiet = mResourceQuiet;
00910   mResourceQuiet = true;
00911 
00912   KMMessage* msg = findMessageBySerNum( sernum, f );
00913   if( msg ) {
00914     // Message found - look for the attachment:
00915 
00916     DwBodyPart* part = findBodyPart( *msg, filename );
00917     if ( part ) {
00918       // Save the contents of the attachment.
00919       KMMessagePart aPart;
00920       msg->bodyPart( part, &aPart );
00921       QByteArray rawData( aPart.bodyDecodedBinary() );
00922 
00923       KTempFile file;
00924       file.file()->writeBlock( rawData.data(), rawData.size() );
00925 
00926       url.setPath( file.name() );
00927 
00928       bOK = true;
00929     }
00930 
00931     if( !bOK ){
00932       kdDebug(5006) << "Attachment " << filename << " not found." << endl;
00933     }
00934   }else{
00935     kdDebug(5006) << "Message not found." << endl;
00936   }
00937 
00938   mResourceQuiet = quiet;
00939   return url;
00940 }
00941 
00942 QStringList KMailICalIfaceImpl::listAttachments(const QString & resource, Q_UINT32 sernum)
00943 {
00944   QStringList rv;
00945   if( !mUseResourceIMAP )
00946     return rv;
00947 
00948   // Find the folder
00949   KMFolder* f = findResourceFolder( resource );
00950   if( !f ) {
00951     kdError(5006) << "listAttachments(" << resource << ") : Not an IMAP resource folder" << endl;
00952     return rv;
00953   }
00954   if ( storageFormat( f ) != StorageXML ) {
00955     kdError(5006) << "listAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
00956     return rv;
00957   }
00958 
00959   KMMessage* msg = findMessageBySerNum( sernum, f );
00960   if( msg ) {
00961     for ( DwBodyPart* part = msg->getFirstDwBodyPart(); part; part = part->Next() ) {
00962       if ( part->hasHeaders() ) {
00963         QString name;
00964         DwMediaType& contentType = part->Headers().ContentType();
00965         if ( QString( contentType.SubtypeStr().c_str() ).startsWith( "x-vnd.kolab." )
00966            || QString( contentType.SubtypeStr().c_str() ).contains( "tnef" ) )
00967           continue;
00968         if ( !part->Headers().ContentDisposition().Filename().empty() )
00969           name = part->Headers().ContentDisposition().Filename().c_str();
00970         else if ( !contentType.Name().empty() )
00971           name = contentType.Name().c_str();
00972         if ( !name.isEmpty() )
00973           rv.append( name );
00974       }
00975     }
00976   } else {
00977     kdDebug(5006) << "Message not found." << endl;
00978   }
00979 
00980   return rv;
00981 }
00982 
00983 
00984 // ============================================================================
00985 
00986 /* KMail part of the interface. These slots are connected to the resource
00987  * folders and inform us of folders or incidences in them changing, being
00988  * added or going away. */
00989 
00990 void KMailICalIfaceImpl::slotFolderRemoved( KMFolder* folder )
00991 {
00992   // pretend the folder just changed back to the mail type, which
00993   // does the right thing, namely remove resource
00994   folderContentsTypeChanged( folder, KMail::ContentsTypeMail );
00995   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
00996   configGroup.deleteEntry( folder->idString() + "-storageFormat" );
00997   configGroup.deleteEntry( folder->idString() + "-changes" );
00998 }
00999 
01000 // KMail added a file to one of the groupware folders
01001 void KMailICalIfaceImpl::slotIncidenceAdded( KMFolder* folder,
01002                                              Q_UINT32 sernum )
01003 {
01004   if( mResourceQuiet || !mUseResourceIMAP )
01005     return;
01006 
01007 //  kdDebug(5006) << "KMailICalIfaceImpl::slotIncidenceAdded" << endl;
01008   QString type = folderContentsType( folder->storage()->contentsType() );
01009   if( type.isEmpty() ) {
01010     kdError(5006) << "Not an IMAP resource folder" << endl;
01011     return;
01012   }
01013   // Get the index of the mail
01014   int i = 0;
01015   KMFolder* aFolder = 0;
01016   KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
01017   assert( folder == aFolder );
01018 
01019   bool unget = !folder->isMessage( i );
01020   QString s;
01021   QString uid( "UID" );
01022   KMMessage *msg = folder->getMsg( i );
01023   if( !msg ) return;
01024   if( msg->isComplete() ) {
01025 
01026     bool ok = false;
01027     StorageFormat format = storageFormat( folder );
01028     switch( format ) {
01029       case StorageIcalVcard:
01030         // Read the iCal or vCard
01031         ok = vPartFoundAndDecoded( msg, s );
01032         if ( ok )
01033           vPartMicroParser( s, uid );
01034         break;
01035       case StorageXML:
01036         // Read the XML from the attachment with the given mimetype
01037         if ( kolabXMLFoundAndDecoded( *msg,
01038               folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
01039           uid = msg->subject();
01040           ok = true;
01041         }
01042         break;
01043     }
01044     if ( !ok ) {
01045       if ( unget )
01046         folder->unGetMsg( i );
01047       return;
01048     }
01049     const Q_UINT32 sernum = msg->getMsgSerNum();
01050     mUIDToSerNum.insert( uid, sernum );
01051 
01052     // tell the resource if we didn't trigger this ourselves
01053     if ( mInTransit.contains( uid ) ) {
01054       mInTransit.remove( uid );
01055     }
01056     incidenceAdded( type, folder->location(), sernum, format, s );
01057   } else {
01058     // go get the rest of it, then try again
01059     // TODO: Till, port me
01060     if ( unget ) mTheUnGetMes.insert( msg->getMsgSerNum(), true );
01061     FolderJob *job = msg->parent()->createJob( msg );
01062     connect( job, SIGNAL( messageRetrieved( KMMessage* ) ),
01063         this, SLOT( slotMessageRetrieved( KMMessage* ) ) );
01064     job->start();
01065     return;
01066   }
01067   if( unget ) folder->unGetMsg(i);
01068 }
01069 
01070 // KMail deleted a file
01071 void KMailICalIfaceImpl::slotIncidenceDeleted( KMFolder* folder,
01072                                                Q_UINT32 sernum )
01073 {
01074   if( mResourceQuiet || !mUseResourceIMAP )
01075     return;
01076 
01077   QString type = folderContentsType( folder->storage()->contentsType() );
01078   //kdDebug(5006) << folder << " " << type << " " << sernum << endl;
01079   if( !type.isEmpty() ) {
01080     // Get the index of the mail
01081     int i = 0;
01082     KMFolder* aFolder = 0;
01083     KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
01084     assert( folder == aFolder );
01085 
01086     // Read the iCal or vCard
01087     bool unget = !folder->isMessage( i );
01088     QString s;
01089     bool ok = false;
01090     KMMessage* msg = folder->getMsg( i );
01091     QString uid( "UID" );
01092     switch( storageFormat( folder ) ) {
01093     case StorageIcalVcard:
01094         if( vPartFoundAndDecoded( msg, s ) ) {
01095             vPartMicroParser( s, uid );
01096             ok = true;
01097         }
01098         break;
01099     case StorageXML:
01100         if ( kolabXMLFoundAndDecoded( *msg, folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
01101           uid = msg->subject();
01102           ok = true;
01103         }
01104         break;
01105     }
01106     if ( ok ) {
01107         kdDebug(5006) << "Emitting DCOP signal incidenceDeleted( "
01108                       << type << ", " << folder->location() << ", " << uid
01109                       << " )" << endl;
01110         incidenceDeleted( type, folder->location(), uid );
01111     }
01112     if( unget ) folder->unGetMsg(i);
01113   } else
01114     kdError(5006) << "Not a groupware folder" << endl;
01115 }
01116 
01117 // KMail orders a refresh
01118 void KMailICalIfaceImpl::slotRefresh( const QString& type )
01119 {
01120   if( mUseResourceIMAP ) {
01121     signalRefresh( type, QString::null /* PENDING(bo) folder->location() */ );
01122     kdDebug(5006) << "Emitting DCOP signal signalRefresh( " << type << " )" << endl;
01123   }
01124 }
01125 
01126 // This is among other things called when an expunge of a folder happens
01127 void KMailICalIfaceImpl::slotRefreshFolder( KMFolder* folder)
01128 {
01129   // TODO: The resources would of course be better off, if only this
01130   // folder would need refreshing. Currently it just orders a reload of
01131   // the type of the folder
01132   if( mUseResourceIMAP && folder ) {
01133     if( folder == mCalendar || folder == mContacts
01134         || folder == mNotes || folder == mTasks
01135         || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01136       // Refresh the folder of this type
01137       KMail::FolderContentsType ct = folder->storage()->contentsType();
01138       slotRefresh( s_folderContentsType[ct].contentsTypeStr );
01139     }
01140   }
01141 }
01142 
01143 /****************************
01144  * The folder and message stuff code
01145  */
01146 
01147 KMFolder* KMailICalIfaceImpl::folderFromType( const QString& type,
01148                                               const QString& folder )
01149 {
01150   if( mUseResourceIMAP ) {
01151     KMFolder* f = 0;
01152     if ( !folder.isEmpty() ) {
01153       f = extraFolder( type, folder );
01154       if ( f )
01155         return f;
01156     }
01157 
01158     if( type == "Calendar" ) f = mCalendar;
01159     else if( type == "Contact" ) f = mContacts;
01160     else if( type == "Note" ) f = mNotes;
01161     else if( type == "Task" || type == "Todo" ) f = mTasks;
01162     else if( type == "Journal" ) f = mJournals;
01163 
01164     if ( f && ( folder.isEmpty() || folder == f->location() ) )
01165       return f;
01166 
01167     kdError(5006) << "No folder ( " << type << ", " << folder << " )\n";
01168   }
01169 
01170   return 0;
01171 }
01172 
01173 
01174 // Returns true if folder is a resource folder. If the resource isn't enabled
01175 // this always returns false
01176 bool KMailICalIfaceImpl::isResourceFolder( KMFolder* folder ) const
01177 {
01178   return mUseResourceIMAP && folder &&
01179     ( isStandardResourceFolder( folder ) || mExtraFolders.find( folder->location() )!=0 );
01180 }
01181 
01182 bool KMailICalIfaceImpl::isStandardResourceFolder( KMFolder* folder ) const
01183 {
01184   return ( folder == mCalendar || folder == mTasks || folder == mJournals ||
01185            folder == mNotes || folder == mContacts );
01186 }
01187 
01188 bool KMailICalIfaceImpl::hideResourceFolder( KMFolder* folder ) const
01189 {
01190   return mHideFolders && isResourceFolder( folder );
01191 }
01192 
01193 bool KMailICalIfaceImpl::hideResourceAccountRoot( KMFolder* folder ) const
01194 {
01195   KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
01196   bool hide = dimapFolder && mHideFolders
01197        && (int)dimapFolder->account()->id() == GlobalSettings::self()->theIMAPResourceAccount()
01198        && GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount();
01199   return hide;
01200 
01201 }
01202 
01203 KFolderTreeItem::Type KMailICalIfaceImpl::folderType( KMFolder* folder ) const
01204 {
01205   if( mUseResourceIMAP && folder ) {
01206     if( folder == mCalendar || folder == mContacts
01207         || folder == mNotes || folder == mTasks
01208         || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01209       KMail::FolderContentsType ct = folder->storage()->contentsType();
01210       return s_folderContentsType[ct].treeItemType;
01211     }
01212   }
01213 
01214   return KFolderTreeItem::Other;
01215 }
01216 
01217 // Global tables of foldernames is different languages
01218 // For now: 0->English, 1->German, 2->French, 3->Dutch
01219 static QMap<KFolderTreeItem::Type,QString> folderNames[4];
01220 QString KMailICalIfaceImpl::folderName( KFolderTreeItem::Type type, int language ) const
01221 {
01222   // With the XML storage, folders are always (internally) named in English
01223   if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
01224     language = 0;
01225 
01226   static bool folderNamesSet = false;
01227   if( !folderNamesSet ) {
01228     folderNamesSet = true;
01229     /* NOTE: If you add something here, you also need to update
01230        GroupwarePage in configuredialog.cpp */
01231 
01232     // English
01233     folderNames[0][KFolderTreeItem::Calendar] = QString::fromLatin1("Calendar");
01234     folderNames[0][KFolderTreeItem::Tasks] = QString::fromLatin1("Tasks");
01235     folderNames[0][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01236     folderNames[0][KFolderTreeItem::Contacts] = QString::fromLatin1("Contacts");
01237     folderNames[0][KFolderTreeItem::Notes] = QString::fromLatin1("Notes");
01238 
01239     // German
01240     folderNames[1][KFolderTreeItem::Calendar] = QString::fromLatin1("Kalender");
01241     folderNames[1][KFolderTreeItem::Tasks] = QString::fromLatin1("Aufgaben");
01242     folderNames[1][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01243     folderNames[1][KFolderTreeItem::Contacts] = QString::fromLatin1("Kontakte");
01244     folderNames[1][KFolderTreeItem::Notes] = QString::fromLatin1("Notizen");
01245 
01246     // French
01247     folderNames[2][KFolderTreeItem::Calendar] = QString::fromLatin1("Calendrier");
01248     folderNames[2][KFolderTreeItem::Tasks] = QString::fromLatin1("Tâches");
01249     folderNames[2][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01250     folderNames[2][KFolderTreeItem::Contacts] = QString::fromLatin1("Contacts");
01251     folderNames[2][KFolderTreeItem::Notes] = QString::fromLatin1("Notes");
01252 
01253     // Dutch
01254     folderNames[3][KFolderTreeItem::Calendar] = QString::fromLatin1("Agenda");
01255     folderNames[3][KFolderTreeItem::Tasks] = QString::fromLatin1("Taken");
01256     folderNames[3][KFolderTreeItem::Journals] = QString::fromLatin1("Logboek");
01257     folderNames[3][KFolderTreeItem::Contacts] = QString::fromLatin1("Contactpersonen");
01258     folderNames[3][KFolderTreeItem::Notes] = QString::fromLatin1("Notities");
01259   }
01260 
01261   if( language < 0 || language > 3 ) {
01262     return folderNames[mFolderLanguage][type];
01263   }
01264   else {
01265     return folderNames[language][type];
01266   }
01267 }
01268 
01269 
01270 // Find message matching a given UID
01271 KMMessage *KMailICalIfaceImpl::findMessageByUID( const QString& uid, KMFolder* folder )
01272 {
01273   if( !folder || !mUIDToSerNum.contains( uid ) ) return 0;
01274   int i;
01275   KMFolder *aFolder;
01276   KMMsgDict::instance()->getLocation( mUIDToSerNum[uid], &aFolder, &i );
01277   Q_ASSERT( aFolder == folder );
01278   return folder->getMsg( i );
01279 }
01280 
01281 // Find message matching a given serial number
01282 KMMessage *KMailICalIfaceImpl::findMessageBySerNum( Q_UINT32 serNum, KMFolder* folder )
01283 {
01284   if( !folder ) return 0;
01285 
01286   KMMessage *message = 0;
01287   KMFolder* aFolder = 0;
01288   int index;
01289   KMMsgDict::instance()->getLocation( serNum, &aFolder, &index );
01290 
01291   if( aFolder && aFolder != folder ) {
01292     kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) found it in folder " << aFolder->location() << ", expected " << folder->location() << endl;
01293   } else {
01294     if( aFolder )
01295       message = aFolder->getMsg( index );
01296     if (!message)
01297       kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) invalid serial number\n" << endl;
01298   }
01299   return message;
01300 }
01301 
01302 void KMailICalIfaceImpl::deleteMsg( KMMessage *msg )
01303 {
01304   if( !msg ) return;
01305   // Commands are now delayed; can't use that anymore, we need immediate deletion
01306   //( new KMDeleteMsgCommand( msg->parent(), msg ) )->start();
01307   KMFolder *srcFolder = msg->parent();
01308   int idx = srcFolder->find(msg);
01309   assert(idx != -1);
01310   srcFolder->removeMsg(idx);
01311   delete msg;
01312   addFolderChange( srcFolder, Contents );
01313 }
01314 
01315 void KMailICalIfaceImpl::folderContentsTypeChanged( KMFolder* folder,
01316                                                     KMail::FolderContentsType contentsType )
01317 {
01318   if ( !mUseResourceIMAP )
01319     return;
01320 //  kdDebug(5006) << "folderContentsTypeChanged( " << folder->name()
01321 //                << ", " << contentsType << ")\n";
01322 
01323   // The builtins can't change type
01324   if ( isStandardResourceFolder( folder ) )
01325     return;
01326 
01327   // Check if already know that 'extra folder'
01328   const QString location = folder->location();
01329   ExtraFolder* ef = mExtraFolders.find( location );
01330   if ( ef && ef->folder ) {
01331     // Notify that the old folder resource is no longer available
01332     subresourceDeleted(folderContentsType( folder->storage()->contentsType() ), location );
01333 
01334     if ( contentsType == 0 ) {
01335       // Delete the old entry, stop listening and stop here
01336       mExtraFolders.remove( location );
01337       folder->disconnect( this );
01338       return;
01339     }
01340     // So the type changed to another groupware type, ok.
01341   } else {
01342     if ( ef && !ef->folder ) // deleted folder, clean up
01343       mExtraFolders.remove( location );
01344     if ( contentsType == 0 )
01345         return;
01346 
01347     //kdDebug(5006) << "registering " << location << " as extra folder" << endl;
01348     // Make a new entry for the list
01349     ef = new ExtraFolder( folder );
01350     mExtraFolders.insert( location, ef );
01351 
01352     FolderInfo info = readFolderInfo( folder );
01353     mFolderInfoMap.insert( folder, info );
01354 
01355     // Adjust the folder names of all foo.default folders.
01356     // German users will get Kalender as the name of all default Calendar folders,
01357     // including their own, so that the default calendar folder of their Japanese
01358     // coworker appears as /user/hirohito/Kalender, although Hirohito sees his folder
01359     // in Japanese. On the server the folders are always in English.
01360     if ( folder->folderType() == KMFolderTypeCachedImap ) {
01361       QString annotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
01362       kdDebug(5006) << "folderContentsTypeChanged: " << folder->name() << " has annotation " << annotation << endl;
01363       if ( annotation == QString( s_folderContentsType[contentsType].annotation ) + ".default" )
01364         folder->setLabel( localizedDefaultFolderName( contentsType ) );
01365     }
01366 
01367     connectFolder( folder );
01368   }
01369   // Tell about the new resource
01370   subresourceAdded( folderContentsType( contentsType ), location, subresourceLabelForPresentation(folder),
01371                     !folder->isReadOnly(), folderIsAlarmRelevant( folder ) );
01372 }
01373 
01374 KMFolder* KMailICalIfaceImpl::extraFolder( const QString& type,
01375                                            const QString& folder )
01376 {
01377   // If an extra folder exists that matches the type and folder location,
01378   // use that
01379   int t = folderContentsType( type );
01380   if ( t < 1 || t > 5 )
01381     return 0;
01382 
01383   ExtraFolder* ef = mExtraFolders.find( folder );
01384   if ( ef && ef->folder && ef->folder->storage()->contentsType() == t )
01385     return ef->folder;
01386 
01387   return 0;
01388 }
01389 
01390 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( KMFolder* folder ) const
01391 {
01392   FolderInfoMap::ConstIterator it = mFolderInfoMap.find( folder );
01393   if ( it != mFolderInfoMap.end() )
01394     return (*it).mStorageFormat;
01395   return globalStorageFormat();
01396 }
01397 
01398 void KMailICalIfaceImpl::setStorageFormat( KMFolder* folder, StorageFormat format )
01399 {
01400   FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01401   if ( it != mFolderInfoMap.end() ) {
01402     (*it).mStorageFormat = format;
01403   } else {
01404     FolderInfo info( format, NoChange );
01405     mFolderInfoMap.insert( folder, info );
01406   }
01407   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01408   configGroup.writeEntry( folder->idString() + "-storageFormat",
01409                           format == StorageXML ? "xml" : "icalvcard" );
01410 }
01411 
01412 void KMailICalIfaceImpl::addFolderChange( KMFolder* folder, FolderChanges changes )
01413 {
01414   FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01415   if ( it != mFolderInfoMap.end() ) {
01416     (*it).mChanges = static_cast<FolderChanges>( (*it).mChanges | changes );
01417   } else { // Otherwise, well, it's a folder we don't care about.
01418     kdDebug(5006) << "addFolderChange: nothing known about folder " << folder->location() << endl;
01419   }
01420   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01421   configGroup.writeEntry( folder->idString() + "-changes", (*it).mChanges );
01422 }
01423 
01424 KMailICalIfaceImpl::FolderInfo KMailICalIfaceImpl::readFolderInfo( const KMFolder * const folder ) const
01425 {
01426   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01427   QString str = configGroup.readEntry( folder->idString() + "-storageFormat", "unset" );
01428   FolderInfo info;
01429   if ( str == "unset" ) {
01430     info.mStorageFormat = globalStorageFormat();
01431     configGroup.writeEntry( folder->idString() + "-storageFormat",
01432                             info.mStorageFormat == StorageXML ? "xml" : "icalvcard" );
01433   } else {
01434     info.mStorageFormat = ( str == "xml" ) ? StorageXML : StorageIcalVcard;
01435   }
01436   info.mChanges = (FolderChanges) configGroup.readNumEntry( folder->idString() + "-changes" );
01437   return info;
01438 }
01439 
01440 
01441 void KMailICalIfaceImpl::folderSynced( KMFolder* folder, const KURL& folderURL )
01442 {
01443   FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01444   if ( it != mFolderInfoMap.end() && (*it).mChanges ) {
01445     handleFolderSynced( folder, folderURL, (*it).mChanges );
01446     (*it).mChanges = NoChange;
01447   }
01448 }
01449 
01450 void KMailICalIfaceImpl::handleFolderSynced( KMFolder* folder,
01451                                              const KURL& folderURL,
01452                                              int _changes )
01453 {
01454   // This is done here instead of in the resource, because
01455   // there could be 0, 1, or N kolab resources at this point.
01456   // We can hack the N case, but not the 0 case.
01457   // So the idea of a DCOP signal for this wouldn't work.
01458   if ( ( _changes & KMailICalIface::Contents ) ||
01459        ( _changes & KMailICalIface::ACL ) ) {
01460     if ( storageFormat( folder ) == StorageXML && folder->storage()->contentsType() == KMail::ContentsTypeCalendar )
01461       triggerKolabFreeBusy( folderURL );
01462   }
01463 }
01464 
01465 void KMailICalIfaceImpl::folderDeletedOnServer( const KURL& folderURL )
01466 {
01467   triggerKolabFreeBusy( folderURL );
01468 }
01469 
01470 void KMailICalIfaceImpl::triggerKolabFreeBusy( const KURL& folderURL )
01471 {
01472   /* Steffen said: you must issue an authenticated HTTP GET request to
01473      https://kolabserver/freebusy/trigger/user@domain/Folder/NestedFolder.pfb
01474      (replace .pfb with .xpfb for extended fb lists). */
01475   KURL httpURL( folderURL );
01476   // Keep username ("user@domain"), pass, and host from the imap url
01477   httpURL.setProtocol( "https" );
01478   httpURL.setPort( 0 ); // remove imap port
01479 
01480   // IMAP path is either /INBOX/<path> or /user/someone/<path>
01481   QString path = folderURL.path( -1 );
01482   Q_ASSERT( path.startsWith( "/" ) );
01483   int secondSlash = path.find( '/', 1 );
01484   if ( secondSlash == -1 ) {
01485     kdWarning() << "KCal::ResourceKolab::fromKMailFolderSynced path is too short: " << path << endl;
01486     return;
01487   }
01488   if ( path.startsWith( "/INBOX/", false ) ) {
01489     // If INBOX, replace it with the username (which is user@domain)
01490     path = path.mid( secondSlash );
01491     path.prepend( folderURL.user() );
01492   } else {
01493     // If user, just remove it. So we keep the IMAP-returned username.
01494     // This assumes it's a known user on the same domain.
01495     path = path.mid( secondSlash );
01496   }
01497 
01498   httpURL.setPath( "/freebusy/trigger/" + path + ".pfb" );
01499   httpURL.setQuery( QString::null );
01500   // Ensure that we encode everything with UTF8
01501   httpURL = KURL( httpURL.url(0,106), 106 );
01502   kdDebug() << "Triggering PFB update for " << folderURL << " : getting " << httpURL << endl;
01503   // "Fire and forget". No need for error handling, nor for explicit deletion.
01504   // Maybe we should try to prevent launching it if it's already running (for this URL) though.
01505   /*KIO::Job* job =*/ KIO::get( httpURL, false, false /*no progress info*/ );
01506 }
01507 
01508 void KMailICalIfaceImpl::slotFolderPropertiesChanged( KMFolder* folder )
01509 {
01510   if ( isResourceFolder( folder ) ) {
01511     const QString location = folder->location();
01512     const QString contentsTypeStr = folderContentsType( folder->storage()->contentsType() );
01513     subresourceDeleted( contentsTypeStr, location );
01514 
01515     subresourceAdded( contentsTypeStr, location, subresourceLabelForPresentation( folder ),
01516                       !folder->isReadOnly(), folderIsAlarmRelevant( folder ) );
01517 
01518   }
01519 }
01520 
01521 // Must only be connected to a signal from KMFolder!
01522 void KMailICalIfaceImpl::slotFolderRenamed()
01523 {
01524   const KMFolder* folder = static_cast<const KMFolder *>( sender() );
01525   slotFolderPropertiesChanged( const_cast<KMFolder*>( folder ) );
01526 }
01527 
01528 void KMailICalIfaceImpl::slotFolderLocationChanged( const QString &oldLocation,
01529                                                     const QString &newLocation )
01530 {
01531   KMFolder *folder = findResourceFolder( oldLocation );
01532   ExtraFolder* ef = mExtraFolders.find( oldLocation );
01533   if ( ef ) {
01534     // reuse the ExtraFolder entry, but adjust the key
01535     mExtraFolders.setAutoDelete( false );
01536     mExtraFolders.remove( oldLocation );
01537     mExtraFolders.setAutoDelete( true );
01538     mExtraFolders.insert( newLocation, ef );
01539   }
01540   if (  folder )
01541     subresourceDeleted( folderContentsType(  folder->storage()->contentsType() ), oldLocation );
01542 
01543 }
01544 
01545 KMFolder* KMailICalIfaceImpl::findResourceFolder( const QString& resource )
01546 {
01547   // Try the standard folders
01548   if( mCalendar && mCalendar->location() == resource )
01549     return mCalendar;
01550   if ( mContacts && mContacts->location() == resource )
01551     return mContacts;
01552   if ( mNotes && mNotes->location() == resource )
01553     return mNotes;
01554   if ( mTasks && mTasks->location() == resource )
01555     return mTasks;
01556   if ( mJournals && mJournals->location() == resource )
01557     return mJournals;
01558 
01559   // No luck. Try the extrafolders
01560   ExtraFolder* ef = mExtraFolders.find( resource );
01561   if ( ef )
01562     return ef->folder;
01563 
01564   // No luck at all
01565   return 0;
01566 }
01567 
01568 /****************************
01569  * The config stuff
01570  */
01571 
01572 void KMailICalIfaceImpl::readConfig()
01573 {
01574   bool enabled = GlobalSettings::self()->theIMAPResourceEnabled() &&
01575                  ( GlobalSettings::self()->theIMAPResourceAccount() != 0 );
01576 
01577   if( !enabled ) {
01578     if( mUseResourceIMAP == true ) {
01579       // Shutting down
01580       mUseResourceIMAP = false;
01581       cleanup();
01582       reloadFolderTree();
01583     }
01584     return;
01585   }
01586   mUseResourceIMAP = enabled;
01587 
01588   // Read remaining options
01589   const bool hideFolders = GlobalSettings::self()->hideGroupwareFolders();
01590   QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01591 
01592   // Find the folder parent
01593   KMFolderDir* folderParentDir;
01594   KMFolderType folderType;
01595   KMFolder* folderParent = kmkernel->findFolderById( parentName );
01596   if( folderParent == 0 ) {
01597     // Parent folder not found. It was probably deleted. The user will have to
01598     // configure things again.
01599     kdDebug(5006) << "Groupware folder " << parentName << " not found. Groupware functionality disabled" << endl;
01600     // Or maybe the inbox simply wasn't created on the first startup
01601     KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01602     Q_ASSERT( account );
01603     if ( account ) {
01604       // just in case we were connected already
01605       disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01606                this, SLOT( slotCheckDone() ) );
01607       connect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01608                this, SLOT( slotCheckDone() ) );
01609     }
01610     mUseResourceIMAP = false;
01611     // We can't really call cleanup(), if those folders were completely deleted.
01612     mCalendar = 0;
01613     mTasks    = 0;
01614     mJournals = 0;
01615     mContacts = 0;
01616     mNotes    = 0;
01617     return;
01618   } else {
01619     folderParentDir = folderParent->createChildFolder();
01620     folderType = folderParent->folderType();
01621   }
01622 
01623   KMAcctCachedImap::GroupwareType groupwareType = dynamic_cast<KMFolderCachedImap *>( folderParent->storage() )->account()->groupwareType();
01624 
01625   if ( groupwareType == KMAcctCachedImap::GroupwareKolab ) {
01626     // Make sure the folder parent has the subdirs
01627     // Globally there are 3 cases: nothing found, some stuff found by type/name heuristics, or everything found OK
01628     bool noneFound = true;
01629     bool mustFix = false; // true when at least one was found by heuristics
01630     QValueVector<StandardFolderSearchResult> results( KMail::ContentsTypeLast + 1 );
01631     for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01632       if ( i != KMail::ContentsTypeMail ) {
01633         results[i] = findStandardResourceFolder( folderParentDir, static_cast<KMail::FolderContentsType>(i) );
01634         if ( results[i].found == StandardFolderSearchResult::FoundAndStandard )
01635           noneFound = false;
01636         else if ( results[i].found == StandardFolderSearchResult::FoundByType ||
01637                   results[i].found == StandardFolderSearchResult::FoundByName ) {
01638           mustFix = true;
01639           noneFound = false;
01640         } else // NotFound
01641           mustFix = true;
01642       }
01643     }
01644 
01645     // Check if something changed
01646     if( mUseResourceIMAP && !noneFound && !mustFix && mFolderParentDir == folderParentDir
01647         && mFolderType == folderType ) {
01648       // Nothing changed
01649       if ( hideFolders != mHideFolders ) {
01650         // Well, the folder hiding has changed
01651         mHideFolders = hideFolders;
01652         reloadFolderTree();
01653       }
01654       return;
01655     }
01656 
01657     if( noneFound || mustFix ) {
01658       QString msg;
01659       QString parentFolderName = folderParent != 0 ? folderParent->name() : folderParentDir->name();
01660       if ( noneFound ) {
01661         // No subfolder was found, so ask if we can make them
01662         msg = i18n("KMail will now create the required groupware folders"
01663                    " as subfolders of %1; if you do not want this, cancel"
01664                    " and the IMAP resource will be disabled").arg(parentFolderName);
01665       } else {
01666         // Some subfolders were found, be more precise
01667         QString operations = "<ul>";
01668         for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01669           if ( i != KMail::ContentsTypeMail ) {
01670             QString typeName = localizedDefaultFolderName( static_cast<KMail::FolderContentsType>( i ) );
01671             if ( results[i].found == StandardFolderSearchResult::NotFound )
01672               operations += "<li>" + i18n( "%1: no folder found. It will be created." ).arg( typeName ) + "</li>";
01673             else if ( results[i].found == StandardFolderSearchResult::FoundByType || results[i].found == StandardFolderSearchResult::FoundByName )
01674               operations += "<li>" + i18n( "%1: found folder %2. It will be set as the main groupware folder." ).
01675                             arg( typeName ).arg( results[i].folder->label() ) + "</li>";
01676           }
01677         }
01678         operations += "</ul>";
01679 
01680         msg = i18n("<qt>KMail found the following groupware folders in %1 and needs to perform the following operations: %2"
01681                    "<br>If you do not want this, cancel"
01682                    " and the IMAP resource will be disabled").arg(parentFolderName, operations);
01683 
01684       }
01685 
01686       if( KMessageBox::questionYesNo( 0, msg,
01687                                       i18n("Standard Groupware Folders"), KStdGuiItem::cont(), KStdGuiItem::cancel() ) == KMessageBox::No ) {
01688 
01689         GlobalSettings::self()->setTheIMAPResourceEnabled( false );
01690         mUseResourceIMAP = false;
01691         mFolderParentDir = 0;
01692         mFolderParent = 0;
01693         reloadFolderTree();
01694         return;
01695       }
01696     }
01697 
01698     // Make the new settings work
01699     mUseResourceIMAP = true;
01700     mFolderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
01701     if( mFolderLanguage > 3 ) mFolderLanguage = 0;
01702     mFolderParentDir = folderParentDir;
01703     mFolderParent = folderParent;
01704     mFolderType = folderType;
01705     mHideFolders = hideFolders;
01706 
01707     // Close the previous folders
01708     cleanup();
01709 
01710     // Set the new folders
01711     mCalendar = initFolder( KMail::ContentsTypeCalendar );
01712     mTasks    = initFolder( KMail::ContentsTypeTask );
01713     mJournals = initFolder( KMail::ContentsTypeJournal );
01714     mContacts = initFolder( KMail::ContentsTypeContact );
01715     mNotes    = initFolder( KMail::ContentsTypeNote );
01716 
01717     // Store final annotation (with .default) so that we won't ask again on next startup
01718     if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01719       static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01720     if ( mTasks->folderType() == KMFolderTypeCachedImap )
01721       static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01722     if ( mJournals->folderType() == KMFolderTypeCachedImap )
01723       static_cast<KMFolderCachedImap *>( mJournals->storage() )->updateAnnotationFolderType();
01724     if ( mContacts->folderType() == KMFolderTypeCachedImap )
01725       static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01726     if ( mNotes->folderType() == KMFolderTypeCachedImap )
01727       static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01728 
01729     // BEGIN TILL TODO The below only uses the dimap folder manager, which
01730     // will fail for all other folder types. Adjust.
01731 
01732     kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
01733     kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
01734     kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
01735 
01736     // Find all extra folders
01737     QStringList folderNames;
01738     QValueList<QGuardedPtr<KMFolder> > folderList;
01739     kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
01740     for(QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
01741         it != folderList.end(); ++it)
01742     {
01743       FolderStorage* storage = (*it)->storage();
01744       if ( storage->contentsType() != 0 ) {
01745         folderContentsTypeChanged( *it, storage->contentsType() );
01746       }
01747     }
01748 
01749     // If we just created them, they might have been registered as extra folders temporarily.
01750     // -> undo that.
01751     mExtraFolders.remove( mCalendar->location() );
01752     mExtraFolders.remove( mTasks->location() );
01753     mExtraFolders.remove( mJournals->location() );
01754     mExtraFolders.remove( mContacts->location() );
01755     mExtraFolders.remove( mNotes->location() );
01756 
01757     // END TILL TODO
01758 
01759     subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
01760     subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
01761     subresourceAdded( folderContentsType( KMail::ContentsTypeJournal ), mJournals->location(), mJournals->label(), true, false );
01762     subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
01763     subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
01764   } else if ( groupwareType == KMAcctCachedImap::GroupwareScalix ) {
01765     // Make the new settings work
01766     mUseResourceIMAP = true;
01767     mFolderParentDir = folderParentDir;
01768     mFolderParent = folderParent;
01769     mFolderType = folderType;
01770     mHideFolders = false;
01771 
01772     // Close the previous folders
01773     cleanup();
01774 
01775     // Set the new folders
01776     mCalendar = initScalixFolder( KMail::ContentsTypeCalendar );
01777     mTasks    = initScalixFolder( KMail::ContentsTypeTask );
01778     mJournals = 0;
01779     mContacts = initScalixFolder( KMail::ContentsTypeContact );
01780     mNotes    = initScalixFolder( KMail::ContentsTypeNote );
01781 
01782     // Store final annotation (with .default) so that we won't ask again on next startup
01783     if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01784       static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01785     if ( mTasks->folderType() == KMFolderTypeCachedImap )
01786       static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01787     if ( mContacts->folderType() == KMFolderTypeCachedImap )
01788       static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01789     if ( mNotes->folderType() == KMFolderTypeCachedImap )
01790       static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01791 
01792     // BEGIN TILL TODO The below only uses the dimap folder manager, which
01793     // will fail for all other folder types. Adjust.
01794 
01795     kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
01796     kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
01797     kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
01798 
01799     // Find all extra folders
01800     QStringList folderNames;
01801     QValueList<QGuardedPtr<KMFolder> > folderList;
01802     kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
01803     QValueList<QGuardedPtr<KMFolder> >::iterator it;
01804     for(it = folderList.begin(); it != folderList.end(); ++it)
01805     {
01806       FolderStorage *storage = (*it)->storage();
01807 
01808       if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
01809         KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
01810 
01811         const QString attributes = imapFolder->folderAttributes();
01812         if ( attributes.contains( "X-FolderClass" ) ) {
01813           if ( !attributes.contains( "X-SpecialFolder" ) || (*it)->location().contains( "@" ) ) {
01814             const Scalix::FolderAttributeParser parser( attributes );
01815             if ( !parser.folderClass().isEmpty() ) {
01816               FolderContentsType type = Scalix::Utils::scalixIdToContentsType( parser.folderClass() );
01817               imapFolder->setContentsType( type );
01818               folderContentsTypeChanged( *it, type );
01819             }
01820           }
01821         }
01822       }
01823     }
01824 
01825     // If we just created them, they might have been registered as extra folders temporarily.
01826     // -> undo that.
01827     mExtraFolders.remove( mCalendar->location() );
01828     mExtraFolders.remove( mTasks->location() );
01829     mExtraFolders.remove( mContacts->location() );
01830     mExtraFolders.remove( mNotes->location() );
01831 
01832     // END TILL TODO
01833 
01834     subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
01835     subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
01836     subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
01837     subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
01838   }
01839 
01840   reloadFolderTree();
01841 }
01842 
01843 void KMailICalIfaceImpl::slotCheckDone()
01844 {
01845   QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01846   KMFolder* folderParent = kmkernel->findFolderById( parentName );
01847   //kdDebug(5006) << k_funcinfo << " folderParent=" << folderParent << endl;
01848   if ( folderParent )  // cool it exists now
01849   {
01850     KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01851     if ( account )
01852       disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01853                   this, SLOT( slotCheckDone() ) );
01854     readConfig();
01855   }
01856 }
01857 
01858 KMFolder* KMailICalIfaceImpl::initFolder( KMail::FolderContentsType contentsType )
01859 {
01860   // Figure out what type of folder this is supposed to be
01861   KMFolderType type = mFolderType;
01862   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
01863 
01864   KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
01865   //kdDebug(5006) << "KMailICalIfaceImpl::initFolder " << folderName( itemType ) << endl;
01866 
01867   // Find the folder
01868   StandardFolderSearchResult result = findStandardResourceFolder( mFolderParentDir, contentsType );
01869   KMFolder* folder = result.folder;
01870 
01871   if ( !folder ) {
01872     // The folder isn't there yet - create it
01873     folder =
01874       mFolderParentDir->createFolder( localizedDefaultFolderName( contentsType ), false, type );
01875     if( mFolderType == KMFolderTypeImap ) {
01876       KMFolderImap* parentFolder = static_cast<KMFolderImap*>( mFolderParent->storage() );
01877       parentFolder->createFolder( localizedDefaultFolderName( contentsType ) );
01878       static_cast<KMFolderImap*>( folder->storage() )->setAccount( parentFolder->account() );
01879     }
01880     // Groupware folder created, use the global setting for storage format
01881     setStorageFormat( folder, globalStorageFormat() );
01882   } else {
01883     FolderInfo info = readFolderInfo( folder );
01884     mFolderInfoMap.insert( folder, info );
01885     //kdDebug(5006) << "Found existing folder type " << itemType << " : " << folder->location()  << endl;
01886   }
01887 
01888   if( folder->canAccess() != 0 ) {
01889     KMessageBox::sorry(0, i18n("You do not have read/write permission to your %1 folder.")
01890                        .arg( folderName( itemType ) ) );
01891     return 0;
01892   }
01893   folder->storage()->setContentsType( contentsType );
01894   folder->setSystemFolder( true );
01895   folder->storage()->writeConfig();
01896   folder->open("ifacefolder");
01897   connectFolder( folder );
01898   return folder;
01899 }
01900 
01901 KMFolder* KMailICalIfaceImpl::initScalixFolder( KMail::FolderContentsType contentsType )
01902 {
01903   // Figure out what type of folder this is supposed to be
01904   KMFolderType type = mFolderType;
01905   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
01906 
01907   KMFolder* folder = 0;
01908 
01909   // Find all extra folders
01910   QStringList folderNames;
01911   QValueList<QGuardedPtr<KMFolder> > folderList;
01912   Q_ASSERT( kmkernel );
01913   Q_ASSERT( kmkernel->dimapFolderMgr() );
01914   kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
01915   QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
01916   for(; it != folderList.end(); ++it)
01917   {
01918     FolderStorage *storage = (*it)->storage();
01919 
01920     if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
01921       KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
01922 
01923       const QString attributes = imapFolder->folderAttributes();
01924       if ( attributes.contains( "X-SpecialFolder" ) ) {
01925         const Scalix::FolderAttributeParser parser( attributes );
01926         if ( contentsType == Scalix::Utils::scalixIdToContentsType( parser.folderClass() ) ) {
01927           folder = *it;
01928           break;
01929         }
01930       }
01931     }
01932   }
01933 
01934   if ( !folder ) {
01935     return 0;
01936   } else {
01937     FolderInfo info = readFolderInfo( folder );
01938     mFolderInfoMap.insert( folder, info );
01939     //kdDebug(5006) << "Found existing folder type " << itemType << " : " << folder->location()  << endl;
01940   }
01941 
01942   if( folder->canAccess() != 0 ) {
01943     KMessageBox::sorry(0, i18n("You do not have read/write permission to your folder.") );
01944     return 0;
01945   }
01946   folder->storage()->setContentsType( contentsType );
01947   folder->setSystemFolder( true );
01948   folder->storage()->writeConfig();
01949   folder->open( "scalixfolder" );
01950   connectFolder( folder );
01951   return folder;
01952 }
01953 
01954 void KMailICalIfaceImpl::connectFolder( KMFolder* folder )
01955 {
01956   // avoid multiple connections
01957   disconnect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
01958               this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
01959   disconnect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
01960               this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
01961   disconnect( folder, SIGNAL( expunged( KMFolder* ) ),
01962               this, SLOT( slotRefreshFolder( KMFolder* ) ) );
01963   disconnect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
01964               this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
01965   disconnect( folder, SIGNAL( nameChanged() ),
01966               this, SLOT( slotFolderRenamed() ) );
01967   disconnect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
01968               this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
01969 
01970   // Setup the signals to listen for changes
01971   connect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
01972            this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
01973   connect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
01974            this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
01975   connect( folder, SIGNAL( expunged( KMFolder* ) ),
01976            this, SLOT( slotRefreshFolder( KMFolder* ) ) );
01977   connect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
01978            this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
01979   connect( folder, SIGNAL( nameChanged() ),
01980            this, SLOT( slotFolderRenamed() ) );
01981   connect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
01982            this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
01983 
01984 }
01985 
01986 static void cleanupFolder( KMFolder* folder, KMailICalIfaceImpl* _this )
01987 {
01988   if( folder ) {
01989     folder->setSystemFolder( false );
01990     folder->disconnect( _this );
01991     folder->close("ifacefolder");
01992   }
01993 }
01994 
01995 void KMailICalIfaceImpl::cleanup()
01996 {
01997   cleanupFolder( mContacts, this );
01998   cleanupFolder( mCalendar, this );
01999   cleanupFolder( mNotes, this );
02000   cleanupFolder( mTasks, this );
02001   cleanupFolder( mJournals, this );
02002 
02003   mContacts = mCalendar = mNotes = mTasks = mJournals = 0;
02004 }
02005 
02006 QString KMailICalIfaceImpl::folderPixmap( KFolderTreeItem::Type type ) const
02007 {
02008   if( !mUseResourceIMAP )
02009     return QString::null;
02010 
02011   if( type == KFolderTreeItem::Contacts )
02012     return QString::fromLatin1( "kmgroupware_folder_contacts" );
02013   else if( type == KFolderTreeItem::Calendar )
02014     return QString::fromLatin1( "kmgroupware_folder_calendar" );
02015   else if( type == KFolderTreeItem::Notes )
02016     return QString::fromLatin1( "kmgroupware_folder_notes" );
02017   else if( type == KFolderTreeItem::Tasks )
02018     return QString::fromLatin1( "kmgroupware_folder_tasks" );
02019   else if( type == KFolderTreeItem::Journals )
02020     return QString::fromLatin1( "kmgroupware_folder_journals" );
02021 
02022   return QString::null;
02023 }
02024 
02025 static void reloadFolderTree()
02026 {
02027   // Make the folder tree show the icons or not
02028   kmkernel->folderMgr()->contentsChanged();
02029 }
02030 
02031 // This is a very light-weight and fast 'parser' to retrieve
02032 // a data entry from a vCal taking continuation lines
02033 // into account
02034 static void vPartMicroParser( const QString& str, QString& s )
02035 {
02036   QString line;
02037   uint len = str.length();
02038 
02039   for( uint i=0; i<len; ++i){
02040     if( str[i] == '\r' || str[i] == '\n' ){
02041       if( str[i] == '\r' )
02042         ++i;
02043       if( i+1 < len && str[i+1] == ' ' ){
02044         // found a continuation line, skip it's leading blanc
02045         ++i;
02046       }else{
02047         // found a logical line end, process the line
02048         if( line.startsWith( s ) ) {
02049           s = line.mid( s.length() + 1 );
02050           return;
02051         }
02052         line = "";
02053       }
02054     } else {
02055       line += str[i];
02056     }
02057   }
02058 
02059   // Not found. Clear it
02060   s.truncate(0);
02061 }
02062 
02063 // Returns the first child folder having the given annotation
02064 static KMFolder* findFolderByAnnotation( KMFolderDir* folderParentDir, const QString& annotation )
02065 {
02066     QPtrListIterator<KMFolderNode> it( *folderParentDir );
02067     for ( ; it.current(); ++it ) {
02068       if ( !it.current()->isDir() ) {
02069         KMFolder* folder = static_cast<KMFolder *>( it.current() );
02070         if ( folder->folderType() == KMFolderTypeCachedImap ) {
02071           QString folderAnnotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
02072           //kdDebug(5006) << "findStandardResourceFolder: " << folder->name() << " has annotation " << folderAnnotation << endl;
02073           if ( folderAnnotation == annotation )
02074             return folder;
02075         }
02076       }
02077     }
02078     return 0;
02079 }
02080 
02081 KMailICalIfaceImpl::StandardFolderSearchResult KMailICalIfaceImpl::findStandardResourceFolder( KMFolderDir* folderParentDir, KMail::FolderContentsType contentsType )
02082 {
02083   if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
02084   {
02085     // Look for a folder with an annotation like "event.default"
02086     KMFolder* folder = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) + ".default" );
02087     if ( folder )
02088       return StandardFolderSearchResult( folder, StandardFolderSearchResult::FoundAndStandard );
02089 
02090     // Fallback: look for a folder with an annotation like "event"
02091     folder = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) );
02092     if ( folder )
02093       return StandardFolderSearchResult( folder, StandardFolderSearchResult::FoundByType );
02094 
02095     // Fallback: look for the folder by name (we'll need to change its type)
02096     KMFolderNode* node = folderParentDir->hasNamedFolder( localizedDefaultFolderName( contentsType ) );
02097     if ( node && !node->isDir() )
02098       return StandardFolderSearchResult( static_cast<KMFolder *>( node ), StandardFolderSearchResult::FoundByName );
02099 
02100     kdDebug(5006) << "findStandardResourceFolder: found no resource folder for " << s_folderContentsType[contentsType].annotation << endl;
02101     return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02102   }
02103   else // icalvcard: look up standard resource folders by name
02104   {
02105     KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
02106     unsigned int folderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
02107     if( folderLanguage > 3 ) folderLanguage = 0;
02108     KMFolderNode* node = folderParentDir->hasNamedFolder( folderName( itemType, folderLanguage ) );
02109     if ( !node || node->isDir() )
02110       return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02111     return StandardFolderSearchResult( static_cast<KMFolder*>( node ), StandardFolderSearchResult::FoundAndStandard );
02112   }
02113 }
02114 
02115 /* We treat all folders as relevant wrt alarms for which we have Administer
02116  * rights or for which the "Incidences relevant for everyone" annotation has
02117  * been set. It can be reasonably assumed that those are "ours". All local folders
02118  * must be ours anyhow. */
02119 bool KMailICalIfaceImpl::folderIsAlarmRelevant( const KMFolder *folder )
02120 {
02121   bool administerRights = true;
02122   bool relevantForOwner = true;
02123   bool relevantForEveryone = false;
02124   if ( folder->folderType() == KMFolderTypeImap ) {
02125     const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
02126     administerRights =
02127       imapFolder->userRights() <= 0 || imapFolder->userRights() & KMail::ACLJobs::Administer;
02128   }
02129   if ( folder->folderType() == KMFolderTypeCachedImap ) {
02130     const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
02131     administerRights =
02132       dimapFolder->userRights() <= 0 || dimapFolder->userRights() & KMail::ACLJobs::Administer;
02133     relevantForOwner = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor () == KMFolderCachedImap::IncForAdmins );
02134     relevantForEveryone = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor() == KMFolderCachedImap::IncForReaders );
02135   }
02136 #if 0
02137   kdDebug(5006) << k_funcinfo << endl;
02138   kdDebug(5006) << "Folder: " << folder->label() << " has administer rights: " << administerRights << endl;
02139   kdDebug(5006) << "and is relevant for owner: " << relevantForOwner <<  endl;
02140   kdDebug(5006) << "and relevant for everyone: "  << relevantForEveryone << endl;
02141 #endif
02142   return ( administerRights && relevantForOwner ) || relevantForEveryone;
02143 }
02144 
02145 void KMailICalIfaceImpl::setResourceQuiet(bool q)
02146 {
02147   mResourceQuiet = q;
02148 }
02149 
02150 bool KMailICalIfaceImpl::isResourceQuiet() const
02151 {
02152   return mResourceQuiet;
02153 }
02154 
02155 
02156 bool KMailICalIfaceImpl::addSubresource( const QString& resource,
02157                                          const QString& parent,
02158                                          const QString& contentsType )
02159 {
02160   kdDebug(5006) << "Adding subresource to parent: " << parent << " with name: " << resource << endl;
02161   kdDebug(5006) << "contents type: " << contentsType << endl;
02162   KMFolder *folder = findResourceFolder( parent );
02163   KMFolderDir *parentFolderDir = !parent.isEmpty() && folder ? folder->createChildFolder(): mFolderParentDir;
02164   if ( !parentFolderDir || parentFolderDir->hasNamedFolder( resource ) ) return false;
02165 
02166   KMFolderType type = mFolderType;
02167   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02168 
02169   KMFolder* newFolder = parentFolderDir->createFolder( resource, false, type );
02170   if ( !newFolder ) return false;
02171   if( mFolderType == KMFolderTypeImap )
02172     static_cast<KMFolderImap*>( folder->storage() )->createFolder( resource );
02173 
02174   StorageFormat defaultFormat = GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
02175   setStorageFormat( newFolder, folder ? storageFormat( folder ) : defaultFormat );
02176   newFolder->storage()->setContentsType( folderContentsType( contentsType ) );
02177   newFolder->storage()->writeConfig();
02178   newFolder->open( "ical_subresource" );
02179   connectFolder( newFolder );
02180   reloadFolderTree();
02181 
02182   return true;
02183 }
02184 
02185 bool KMailICalIfaceImpl::removeSubresource( const QString& location )
02186 {
02187   kdDebug(5006) << k_funcinfo << endl;
02188 
02189   KMFolder *folder = findResourceFolder( location );
02190 
02191   // We don't allow the default folders to be deleted, so check for
02192   // those first. It would be nicer to produce a more meaningful error,
02193   // or prevent deletion of the builtin folders from the gui already.
02194   if ( !folder || isStandardResourceFolder( folder ) )
02195       return false;
02196 
02197   // the folder will be removed, which implies closed, so make sure
02198   // nothing is using it anymore first
02199   subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), location );
02200   mExtraFolders.remove( location );
02201   folder->disconnect( this );
02202 
02203   if ( folder->folderType() == KMFolderTypeImap )
02204     kmkernel->imapFolderMgr()->remove( folder );
02205   else if ( folder->folderType() == KMFolderTypeCachedImap ) {
02206     // Deleted by user -> tell the account (see KMFolderCachedImap::listDirectory2)
02207     KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( folder->storage() );
02208     KMAcctCachedImap* acct = storage->account();
02209     if ( acct )
02210       acct->addDeletedFolder( folder );
02211     kmkernel->dimapFolderMgr()->remove( folder );
02212   }
02213   return true;
02214 }
02215 
02216 #include "kmailicalifaceimpl.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys