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 // Builds a folder list from the dimap and the local folder list.
01658 static void createFolderList( QStringList &folderNames, QValueList<QGuardedPtr<KMFolder> > &folderList )
01659 {
01660   QStringList dimapFolderNames;
01661   QStringList localFolderNames;
01662   QValueList<QGuardedPtr<KMFolder> > dimapFolderList;
01663   QValueList<QGuardedPtr<KMFolder> > localFolderList;
01664   kmkernel->dimapFolderMgr()->createFolderList( &dimapFolderNames, &dimapFolderList );
01665   kmkernel->folderMgr()->createFolderList( &localFolderNames, &localFolderList );
01666   folderNames += dimapFolderNames;
01667   folderNames += localFolderNames;
01668   folderList += dimapFolderList;
01669   folderList += localFolderList;
01670 }
01671 
01672 /****************************
01673  * The config stuff
01674  */
01675 
01676 void KMailICalIfaceImpl::readConfig()
01677 {
01678   bool enabled = GlobalSettings::self()->theIMAPResourceEnabled() &&
01679                  ( GlobalSettings::self()->theIMAPResourceAccount() != 0 );
01680 
01681   if( !enabled ) {
01682     if( mUseResourceIMAP == true ) {
01683       // Shutting down
01684       mUseResourceIMAP = false;
01685       cleanup();
01686       reloadFolderTree();
01687     }
01688     return;
01689   }
01690   mUseResourceIMAP = enabled;
01691 
01692   // Read remaining options
01693   const bool hideFolders = GlobalSettings::self()->hideGroupwareFolders();
01694   QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01695 
01696   // Find the folder parent
01697   KMFolderDir* folderParentDir;
01698   KMFolderType folderType;
01699   KMFolder* folderParent = kmkernel->findFolderById( parentName );
01700   if( folderParent == 0 ) {
01701     // Parent folder not found. It was probably deleted. The user will have to
01702     // configure things again.
01703     kdDebug(5006) << "Groupware folder " << parentName << " not found. Groupware functionality disabled" << endl;
01704     // Or maybe the inbox simply wasn't created on the first startup
01705     KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01706     Q_ASSERT( account );
01707     if ( account ) {
01708       // just in case we were connected already
01709       disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01710                this, SLOT( slotCheckDone() ) );
01711       connect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01712                this, SLOT( slotCheckDone() ) );
01713     }
01714     mUseResourceIMAP = false;
01715     // We can't really call cleanup(), if those folders were completely deleted.
01716     mCalendar = 0;
01717     mTasks    = 0;
01718     mJournals = 0;
01719     mContacts = 0;
01720     mNotes    = 0;
01721     return;
01722   } else {
01723     folderParentDir = folderParent->createChildFolder();
01724     folderType = folderParent->folderType();
01725   }
01726 
01727   KMAcctCachedImap::GroupwareType groupwareType = dynamic_cast<KMFolderCachedImap *>( folderParent->storage() )->account()->groupwareType();
01728 
01729   if ( groupwareType == KMAcctCachedImap::GroupwareKolab ) {
01730     // Make sure the folder parent has the subdirs
01731     // Globally there are 3 cases: nothing found, some stuff found by type/name heuristics, or everything found OK
01732     bool noneFound = true;
01733     bool mustFix = false; // true when at least one was found by heuristics
01734     QValueVector<StandardFolderSearchResult> results( KMail::ContentsTypeLast + 1 );
01735     for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01736       if ( i != KMail::ContentsTypeMail ) {
01737         results[i] = findStandardResourceFolder( folderParentDir, static_cast<KMail::FolderContentsType>(i) );
01738         if ( results[i].found == StandardFolderSearchResult::FoundAndStandard )
01739           noneFound = false;
01740         else if ( results[i].found == StandardFolderSearchResult::FoundByType ||
01741                   results[i].found == StandardFolderSearchResult::FoundByName ) {
01742           mustFix = true;
01743           noneFound = false;
01744         } else // NotFound
01745           mustFix = true;
01746       }
01747     }
01748 
01749     // Check if something changed
01750     if( mUseResourceIMAP && !noneFound && !mustFix && mFolderParentDir == folderParentDir
01751         && mFolderType == folderType ) {
01752       // Nothing changed
01753       if ( hideFolders != mHideFolders ) {
01754         // Well, the folder hiding has changed
01755         mHideFolders = hideFolders;
01756         reloadFolderTree();
01757       }
01758       return;
01759     }
01760 
01761     if( noneFound || mustFix ) {
01762       QString msg;
01763       QString parentFolderName = folderParent != 0 ? folderParent->name() : folderParentDir->name();
01764       if ( noneFound ) {
01765         // No subfolder was found, so ask if we can make them
01766         msg = i18n("KMail will now create the required groupware folders"
01767                    " as subfolders of %1; if you do not want this, cancel"
01768                    " and the IMAP resource will be disabled").arg(parentFolderName);
01769       } else {
01770         // Some subfolders were found, be more precise
01771         QString operations = "<ul>";
01772         for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01773           if ( i != KMail::ContentsTypeMail ) {
01774             QString typeName = localizedDefaultFolderName( static_cast<KMail::FolderContentsType>( i ) );
01775             if ( results[i].found == StandardFolderSearchResult::NotFound )
01776               operations += "<li>" + i18n( "%1: no folder found. It will be created." ).arg( typeName ) + "</li>";
01777             else if ( results[i].found == StandardFolderSearchResult::FoundByType || results[i].found == StandardFolderSearchResult::FoundByName )
01778               operations += "<li>" + i18n( "%1: found folder %2. It will be set as the main groupware folder." ).
01779                             arg( typeName ).arg( results[i].folder->label() ) + "</li>";
01780           }
01781         }
01782         operations += "</ul>";
01783 
01784         msg = i18n("<qt>KMail found the following groupware folders in %1 and needs to perform the following operations: %2"
01785                    "<br>If you do not want this, cancel"
01786                    " and the IMAP resource will be disabled").arg(parentFolderName, operations);
01787 
01788       }
01789 
01790       if( KMessageBox::questionYesNo( 0, msg,
01791                                       i18n("Standard Groupware Folders"), KStdGuiItem::cont(), KStdGuiItem::cancel() ) == KMessageBox::No ) {
01792 
01793         GlobalSettings::self()->setTheIMAPResourceEnabled( false );
01794         mUseResourceIMAP = false;
01795         mFolderParentDir = 0;
01796         mFolderParent = 0;
01797         reloadFolderTree();
01798         return;
01799       }
01800     }
01801 
01802     // Make the new settings work
01803     mUseResourceIMAP = true;
01804     mFolderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
01805     if( mFolderLanguage > 3 ) mFolderLanguage = 0;
01806     mFolderParentDir = folderParentDir;
01807     mFolderParent = folderParent;
01808     mFolderType = folderType;
01809     mHideFolders = hideFolders;
01810 
01811     // Close the previous folders
01812     cleanup();
01813 
01814     // Set the new folders
01815     mCalendar = initFolder( KMail::ContentsTypeCalendar );
01816     mTasks    = initFolder( KMail::ContentsTypeTask );
01817     mJournals = initFolder( KMail::ContentsTypeJournal );
01818     mContacts = initFolder( KMail::ContentsTypeContact );
01819     mNotes    = initFolder( KMail::ContentsTypeNote );
01820 
01821     // Store final annotation (with .default) so that we won't ask again on next startup
01822     if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01823       static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01824     if ( mTasks->folderType() == KMFolderTypeCachedImap )
01825       static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01826     if ( mJournals->folderType() == KMFolderTypeCachedImap )
01827       static_cast<KMFolderCachedImap *>( mJournals->storage() )->updateAnnotationFolderType();
01828     if ( mContacts->folderType() == KMFolderTypeCachedImap )
01829       static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01830     if ( mNotes->folderType() == KMFolderTypeCachedImap )
01831       static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01832 
01833     kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
01834     kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
01835     kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
01836 
01837     // Find all extra folders
01838     QStringList folderNames;
01839     QValueList<QGuardedPtr<KMFolder> > folderList;
01840     createFolderList( folderNames, folderList );
01841     for( QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
01842          it != folderList.end(); ++it )
01843     {
01844       FolderStorage *storage = (*it)->storage();
01845       KMFolderCachedImap* dimapStorage = dynamic_cast<KMFolderCachedImap*>( storage );
01846       if ( storage && storage->contentsType() != 0 ) {
01847         if ( dimapStorage )
01848           dimapStorage->updateAnnotationFolderType();
01849         folderContentsTypeChanged( *it, storage->contentsType() );
01850       }
01851     }
01852 
01853     // If we just created them, they might have been registered as extra folders temporarily.
01854     // -> undo that.
01855     mExtraFolders.remove( mCalendar->location() );
01856     mExtraFolders.remove( mTasks->location() );
01857     mExtraFolders.remove( mJournals->location() );
01858     mExtraFolders.remove( mContacts->location() );
01859     mExtraFolders.remove( mNotes->location() );
01860 
01861     subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
01862     subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
01863     subresourceAdded( folderContentsType( KMail::ContentsTypeJournal ), mJournals->location(), mJournals->label(), true, false );
01864     subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
01865     subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
01866   } else if ( groupwareType == KMAcctCachedImap::GroupwareScalix ) {
01867     // Make the new settings work
01868     mUseResourceIMAP = true;
01869     mFolderParentDir = folderParentDir;
01870     mFolderParent = folderParent;
01871     mFolderType = folderType;
01872     mHideFolders = false;
01873 
01874     // Close the previous folders
01875     cleanup();
01876 
01877     // Set the new folders
01878     mCalendar = initScalixFolder( KMail::ContentsTypeCalendar );
01879     mTasks    = initScalixFolder( KMail::ContentsTypeTask );
01880     mJournals = 0;
01881     mContacts = initScalixFolder( KMail::ContentsTypeContact );
01882     mNotes    = initScalixFolder( KMail::ContentsTypeNote );
01883 
01884     // Store final annotation (with .default) so that we won't ask again on next startup
01885     if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01886       static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01887     if ( mTasks->folderType() == KMFolderTypeCachedImap )
01888       static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01889     if ( mContacts->folderType() == KMFolderTypeCachedImap )
01890       static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01891     if ( mNotes->folderType() == KMFolderTypeCachedImap )
01892       static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01893 
01894     // BEGIN TILL TODO The below only uses the dimap folder manager, which
01895     // will fail for all other folder types. Adjust.
01896 
01897     kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
01898     kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
01899     kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
01900 
01901     // Find all extra folders
01902     QStringList folderNames;
01903     QValueList<QGuardedPtr<KMFolder> > folderList;
01904     kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
01905     QValueList<QGuardedPtr<KMFolder> >::iterator it;
01906     for(it = folderList.begin(); it != folderList.end(); ++it)
01907     {
01908       FolderStorage *storage = (*it)->storage();
01909 
01910       if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
01911         KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
01912 
01913         const QString attributes = imapFolder->folderAttributes();
01914         if ( attributes.contains( "X-FolderClass" ) ) {
01915           if ( !attributes.contains( "X-SpecialFolder" ) || (*it)->location().contains( "@" ) ) {
01916             const Scalix::FolderAttributeParser parser( attributes );
01917             if ( !parser.folderClass().isEmpty() ) {
01918               FolderContentsType type = Scalix::Utils::scalixIdToContentsType( parser.folderClass() );
01919               imapFolder->setContentsType( type );
01920               folderContentsTypeChanged( *it, type );
01921             }
01922           }
01923         }
01924       }
01925     }
01926 
01927     // If we just created them, they might have been registered as extra folders temporarily.
01928     // -> undo that.
01929     mExtraFolders.remove( mCalendar->location() );
01930     mExtraFolders.remove( mTasks->location() );
01931     mExtraFolders.remove( mContacts->location() );
01932     mExtraFolders.remove( mNotes->location() );
01933 
01934     // END TILL TODO
01935 
01936     subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
01937     subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
01938     subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
01939     subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
01940   }
01941 
01942   KConfig *config = kmkernel->config();
01943   config->setGroup("Resource UINames");
01944   *KMailICalIfaceImpl::mSubResourceUINamesMap =  config->entryMap( "Resource UINames" );
01945 
01946   reloadFolderTree();
01947 }
01948 
01949 void KMailICalIfaceImpl::slotCheckDone()
01950 {
01951   QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01952   KMFolder* folderParent = kmkernel->findFolderById( parentName );
01953   //kdDebug(5006) << k_funcinfo << " folderParent=" << folderParent << endl;
01954   if ( folderParent )  // cool it exists now
01955   {
01956     KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01957     if ( account )
01958       disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01959                   this, SLOT( slotCheckDone() ) );
01960     readConfig();
01961   }
01962 }
01963 
01964 KMFolder* KMailICalIfaceImpl::initFolder( KMail::FolderContentsType contentsType )
01965 {
01966   // Figure out what type of folder this is supposed to be
01967   KMFolderType type = mFolderType;
01968   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
01969 
01970   KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
01971   //kdDebug(5006) << "KMailICalIfaceImpl::initFolder " << folderName( itemType ) << endl;
01972 
01973   // Find the folder
01974   StandardFolderSearchResult result = findStandardResourceFolder( mFolderParentDir, contentsType );
01975 
01976   // deal with multiple default groupware folders
01977   if ( result.folders.count() > 1 && result.found == StandardFolderSearchResult::FoundAndStandard ) {
01978     QStringList labels;
01979     for ( QValueList<KMFolder*>::ConstIterator it = result.folders.begin(); it != result.folders.end(); ++it )
01980       labels << (*it)->prettyURL();
01981     const QString selected = KInputDialog::getItem( i18n("Default folder"),
01982         i18n("There are multiple %1 default folders, please choose one:")
01983         .arg( localizedDefaultFolderName( contentsType ) ), labels );
01984     if ( !selected.isEmpty() )
01985       result.folder = result.folders[ labels.findIndex( selected ) ];
01986   }
01987 
01988   KMFolder* folder = result.folder;
01989 
01990   if ( !folder ) {
01991     // The folder isn't there yet - create it
01992     folder =
01993       mFolderParentDir->createFolder( localizedDefaultFolderName( contentsType ), false, type );
01994     if( mFolderType == KMFolderTypeImap ) {
01995       KMFolderImap* parentFolder = static_cast<KMFolderImap*>( mFolderParent->storage() );
01996       parentFolder->createFolder( localizedDefaultFolderName( contentsType ) );
01997       static_cast<KMFolderImap*>( folder->storage() )->setAccount( parentFolder->account() );
01998     }
01999     // Groupware folder created, use the global setting for storage format
02000     setStorageFormat( folder, globalStorageFormat() );
02001   } else {
02002     FolderInfo info = readFolderInfo( folder );
02003     mFolderInfoMap.insert( folder, info );
02004     //kdDebug(5006) << "Found existing folder type " << itemType << " : " << folder->location()  << endl;
02005   }
02006 
02007   if( folder->canAccess() != 0 ) {
02008     KMessageBox::sorry(0, i18n("You do not have read/write permission to your %1 folder.")
02009                        .arg( folderName( itemType ) ) );
02010     return 0;
02011   }
02012   folder->storage()->setContentsType( contentsType );
02013   folder->setSystemFolder( true );
02014   folder->storage()->writeConfig();
02015   folder->open("ifacefolder");
02016   connectFolder( folder );
02017   return folder;
02018 }
02019 
02020 KMFolder* KMailICalIfaceImpl::initScalixFolder( KMail::FolderContentsType contentsType )
02021 {
02022   // Figure out what type of folder this is supposed to be
02023   KMFolderType type = mFolderType;
02024   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02025 
02026   KMFolder* folder = 0;
02027 
02028   // Find all extra folders
02029   QStringList folderNames;
02030   QValueList<QGuardedPtr<KMFolder> > folderList;
02031   Q_ASSERT( kmkernel );
02032   Q_ASSERT( kmkernel->dimapFolderMgr() );
02033   kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
02034   QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
02035   for(; it != folderList.end(); ++it)
02036   {
02037     FolderStorage *storage = (*it)->storage();
02038 
02039     if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
02040       KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
02041 
02042       const QString attributes = imapFolder->folderAttributes();
02043       if ( attributes.contains( "X-SpecialFolder" ) ) {
02044         const Scalix::FolderAttributeParser parser( attributes );
02045         if ( contentsType == Scalix::Utils::scalixIdToContentsType( parser.folderClass() ) ) {
02046           folder = *it;
02047           break;
02048         }
02049       }
02050     }
02051   }
02052 
02053   if ( !folder ) {
02054     return 0;
02055   } else {
02056     FolderInfo info = readFolderInfo( folder );
02057     mFolderInfoMap.insert( folder, info );
02058     //kdDebug(5006) << "Found existing folder type " << itemType << " : " << folder->location()  << endl;
02059   }
02060 
02061   if( folder->canAccess() != 0 ) {
02062     KMessageBox::sorry(0, i18n("You do not have read/write permission to your folder.") );
02063     return 0;
02064   }
02065   folder->storage()->setContentsType( contentsType );
02066   folder->setSystemFolder( true );
02067   folder->storage()->writeConfig();
02068   folder->open( "scalixfolder" );
02069   connectFolder( folder );
02070   return folder;
02071 }
02072 
02073 void KMailICalIfaceImpl::connectFolder( KMFolder* folder )
02074 {
02075   // avoid multiple connections
02076   disconnect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
02077               this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
02078   disconnect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
02079               this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
02080   disconnect( folder, SIGNAL( expunged( KMFolder* ) ),
02081               this, SLOT( slotRefreshFolder( KMFolder* ) ) );
02082   disconnect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
02083               this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
02084   disconnect( folder, SIGNAL( nameChanged() ),
02085               this, SLOT( slotFolderRenamed() ) );
02086   disconnect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
02087               this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
02088 
02089   // Setup the signals to listen for changes
02090   connect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
02091            this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
02092   connect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
02093            this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
02094   connect( folder, SIGNAL( expunged( KMFolder* ) ),
02095            this, SLOT( slotRefreshFolder( KMFolder* ) ) );
02096   connect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
02097            this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
02098   connect( folder, SIGNAL( nameChanged() ),
02099            this, SLOT( slotFolderRenamed() ) );
02100   connect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
02101            this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
02102 
02103 }
02104 
02105 static void cleanupFolder( KMFolder* folder, KMailICalIfaceImpl* _this )
02106 {
02107   if( folder ) {
02108     folder->setSystemFolder( false );
02109     folder->disconnect( _this );
02110     folder->close("ifacefolder");
02111   }
02112 }
02113 
02114 void KMailICalIfaceImpl::cleanup()
02115 {
02116   cleanupFolder( mContacts, this );
02117   cleanupFolder( mCalendar, this );
02118   cleanupFolder( mNotes, this );
02119   cleanupFolder( mTasks, this );
02120   cleanupFolder( mJournals, this );
02121 
02122   mContacts = mCalendar = mNotes = mTasks = mJournals = 0;
02123 }
02124 
02125 QString KMailICalIfaceImpl::folderPixmap( KFolderTreeItem::Type type ) const
02126 {
02127   if( !mUseResourceIMAP )
02128     return QString::null;
02129 
02130   if( type == KFolderTreeItem::Contacts )
02131     return QString::fromLatin1( "kmgroupware_folder_contacts" );
02132   else if( type == KFolderTreeItem::Calendar )
02133     return QString::fromLatin1( "kmgroupware_folder_calendar" );
02134   else if( type == KFolderTreeItem::Notes )
02135     return QString::fromLatin1( "kmgroupware_folder_notes" );
02136   else if( type == KFolderTreeItem::Tasks )
02137     return QString::fromLatin1( "kmgroupware_folder_tasks" );
02138   else if( type == KFolderTreeItem::Journals )
02139     return QString::fromLatin1( "kmgroupware_folder_journals" );
02140 
02141   return QString::null;
02142 }
02143 
02144 static void reloadFolderTree()
02145 {
02146   // Make the folder tree show the icons or not
02147   kmkernel->folderMgr()->contentsChanged();
02148 }
02149 
02150 // This is a very light-weight and fast 'parser' to retrieve
02151 // a data entry from a vCal taking continuation lines
02152 // into account
02153 static void vPartMicroParser( const QString& str, QString& s )
02154 {
02155   QString line;
02156   uint len = str.length();
02157 
02158   for( uint i=0; i<len; ++i){
02159     if( str[i] == '\r' || str[i] == '\n' ){
02160       if( str[i] == '\r' )
02161         ++i;
02162       if( i+1 < len && str[i+1] == ' ' ){
02163         // found a continuation line, skip it's leading blanc
02164         ++i;
02165       }else{
02166         // found a logical line end, process the line
02167         if( line.startsWith( s ) ) {
02168           s = line.mid( s.length() + 1 );
02169           return;
02170         }
02171         line = "";
02172       }
02173     } else {
02174       line += str[i];
02175     }
02176   }
02177 
02178   // Not found. Clear it
02179   s.truncate(0);
02180 }
02181 
02182 // Returns the first child folder having the given annotation
02183 static QValueList<KMFolder*> findFolderByAnnotation( KMFolderDir* folderParentDir, const QString& annotation )
02184 {
02185   QValueList<KMFolder*> rv;
02186   QPtrListIterator<KMFolderNode> it( *folderParentDir );
02187   for ( ; it.current(); ++it ) {
02188     if ( !it.current()->isDir() ) {
02189       KMFolder* folder = static_cast<KMFolder *>( it.current() );
02190       if ( folder->folderType() == KMFolderTypeCachedImap ) {
02191         QString folderAnnotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
02192         //kdDebug(5006) << "findStandardResourceFolder: " << folder->name() << " has annotation " << folderAnnotation << endl;
02193         if ( folderAnnotation == annotation )
02194           rv.append( folder );
02195       }
02196     }
02197   }
02198   return rv;
02199 }
02200 
02201 KMailICalIfaceImpl::StandardFolderSearchResult KMailICalIfaceImpl::findStandardResourceFolder( KMFolderDir* folderParentDir, KMail::FolderContentsType contentsType )
02202 {
02203   if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
02204   {
02205     // Look for a folder with an annotation like "event.default"
02206     QValueList<KMFolder*> folders = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) + ".default" );
02207     if ( !folders.isEmpty() )
02208       return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundAndStandard );
02209 
02210     // Fallback: look for a folder with an annotation like "event"
02211     folders = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) );
02212     if ( !folders.isEmpty() )
02213       return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundByType );
02214 
02215     // Fallback: look for the folder by name (we'll need to change its type)
02216     KMFolderNode* node = folderParentDir->hasNamedFolder( localizedDefaultFolderName( contentsType ) );
02217     if ( node && !node->isDir() )
02218       return StandardFolderSearchResult( static_cast<KMFolder *>( node ), StandardFolderSearchResult::FoundByName );
02219 
02220     kdDebug(5006) << "findStandardResourceFolder: found no resource folder for " << s_folderContentsType[contentsType].annotation << endl;
02221     return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02222   }
02223   else // icalvcard: look up standard resource folders by name
02224   {
02225     KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
02226     unsigned int folderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
02227     if( folderLanguage > 3 ) folderLanguage = 0;
02228     KMFolderNode* node = folderParentDir->hasNamedFolder( folderName( itemType, folderLanguage ) );
02229     if ( !node || node->isDir() )
02230       return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02231     return StandardFolderSearchResult( static_cast<KMFolder*>( node ), StandardFolderSearchResult::FoundAndStandard );
02232   }
02233 }
02234 
02235 /* We treat all folders as relevant wrt alarms for which we have Administer
02236  * rights or for which the "Incidences relevant for everyone" annotation has
02237  * been set. It can be reasonably assumed that those are "ours". All local folders
02238  * must be ours anyhow. */
02239 bool KMailICalIfaceImpl::folderIsAlarmRelevant( const KMFolder *folder )
02240 {
02241   bool administerRights = true;
02242   bool relevantForOwner = true;
02243   bool relevantForEveryone = false;
02244   if ( folder->folderType() == KMFolderTypeImap ) {
02245     const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
02246     administerRights =
02247       imapFolder->userRights() <= 0 || imapFolder->userRights() & KMail::ACLJobs::Administer;
02248   }
02249   if ( folder->folderType() == KMFolderTypeCachedImap ) {
02250     const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
02251     administerRights =
02252       dimapFolder->userRights() <= 0 || dimapFolder->userRights() & KMail::ACLJobs::Administer;
02253     relevantForOwner = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor () == KMFolderCachedImap::IncForAdmins );
02254     relevantForEveryone = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor() == KMFolderCachedImap::IncForReaders );
02255   }
02256 #if 0
02257   kdDebug(5006) << k_funcinfo << endl;
02258   kdDebug(5006) << "Folder: " << folder->label() << " has administer rights: " << administerRights << endl;
02259   kdDebug(5006) << "and is relevant for owner: " << relevantForOwner <<  endl;
02260   kdDebug(5006) << "and relevant for everyone: "  << relevantForEveryone << endl;
02261 #endif
02262   return ( administerRights && relevantForOwner ) || relevantForEveryone;
02263 }
02264 
02265 void KMailICalIfaceImpl::setResourceQuiet(bool q)
02266 {
02267   mResourceQuiet = q;
02268 }
02269 
02270 bool KMailICalIfaceImpl::isResourceQuiet() const
02271 {
02272   return mResourceQuiet;
02273 }
02274 
02275 
02276 bool KMailICalIfaceImpl::addSubresource( const QString& resource,
02277                                          const QString& parent,
02278                                          const QString& contentsType )
02279 {
02280   kdDebug(5006) << "Adding subresource to parent: " << parent << " with name: " << resource << endl;
02281   kdDebug(5006) << "contents type: " << contentsType << endl;
02282   KMFolder *folder = findResourceFolder( parent );
02283   KMFolderDir *parentFolderDir = !parent.isEmpty() && folder ? folder->createChildFolder(): mFolderParentDir;
02284   if ( !parentFolderDir || parentFolderDir->hasNamedFolder( resource ) ) return false;
02285 
02286   KMFolderType type = mFolderType;
02287   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02288 
02289   KMFolder* newFolder = parentFolderDir->createFolder( resource, false, type );
02290   if ( !newFolder ) return false;
02291   if( mFolderType == KMFolderTypeImap )
02292     static_cast<KMFolderImap*>( folder->storage() )->createFolder( resource );
02293 
02294   StorageFormat defaultFormat = GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
02295   setStorageFormat( newFolder, folder ? storageFormat( folder ) : defaultFormat );
02296   newFolder->storage()->setContentsType( folderContentsType( contentsType ) );
02297   newFolder->storage()->writeConfig();
02298   newFolder->open( "ical_subresource" );
02299   connectFolder( newFolder );
02300   reloadFolderTree();
02301 
02302   return true;
02303 }
02304 
02305 bool KMailICalIfaceImpl::removeSubresource( const QString& location )
02306 {
02307   kdDebug(5006) << k_funcinfo << endl;
02308 
02309   KMFolder *folder = findResourceFolder( location );
02310 
02311   // We don't allow the default folders to be deleted, so check for
02312   // those first. It would be nicer to produce a more meaningful error,
02313   // or prevent deletion of the builtin folders from the gui already.
02314   if ( !folder || isStandardResourceFolder( folder ) )
02315       return false;
02316 
02317   // the folder will be removed, which implies closed, so make sure
02318   // nothing is using it anymore first
02319   subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), location );
02320   mExtraFolders.remove( location );
02321   folder->disconnect( this );
02322 
02323   if ( folder->folderType() == KMFolderTypeImap )
02324     kmkernel->imapFolderMgr()->remove( folder );
02325   else if ( folder->folderType() == KMFolderTypeCachedImap ) {
02326     // Deleted by user -> tell the account (see KMFolderCachedImap::listDirectory2)
02327     KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( folder->storage() );
02328     KMAcctCachedImap* acct = storage->account();
02329     if ( acct )
02330       acct->addDeletedFolder( folder );
02331     kmkernel->dimapFolderMgr()->remove( folder );
02332   }
02333   return true;
02334 }
02335 
02336 void KMailICalIfaceImpl::syncFolder(KMFolder * folder) const
02337 {
02338   if ( kmkernel->isOffline() || !GlobalSettings::immediatlySyncDIMAPOnGroupwareChanges() )
02339     return;
02340   KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
02341   if ( !dimapFolder )
02342     return;
02343   // check if the folder exists already, otherwise sync its parent as well to create it
02344   if ( dimapFolder->imapPath().isEmpty() ) {
02345     if ( folder->parent() && folder->parent()->owner() )
02346       syncFolder( folder->parent()->owner() );
02347     else
02348       return;
02349   }
02350   dimapFolder->account()->processNewMailInFolder( folder );
02351 }
02352 
02353 #include "kmailicalifaceimpl.moc"