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