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 int KMailICalIfaceImpl::dimapAccounts()
00659 {
00660   return dimapAccountCount();
00661 }
00662 
00663 static QString subresourceLabelForPresentation( const KMFolder * folder )
00664 {
00665     if( KMailICalIfaceImpl::getResourceMap()->contains( folder->location() ) ) {
00666         return folder->label();
00667     }
00668 
00669     QString label = folder->prettyURL();
00670     QStringList parts = QStringList::split( QString::fromLatin1("/"), label );
00671 
00672     // In the common special case of some other user's folder shared with us
00673     // the url looks like "Server Name/user/$USERNAME/Folder/Name". Make
00674     // those a bit nicer.
00675     if ( parts[1] == QString::fromLatin1("user") ) {
00676         QStringList remainder(parts);
00677         remainder.pop_front();
00678         remainder.pop_front();
00679         remainder.pop_front();
00680         label = i18n("%1's %2")
00681             .arg( parts[2] )
00682             .arg( remainder.join( QString::fromLatin1("/") ) );
00683     }
00684     // Another special case is our own folders, under the imap INBOX, make
00685     // those prettier too
00686     const KMFolder *parent = folder;
00687     while ( parent->parent() && parent->parent()->owner() ) {
00688       parent = parent->parent()->owner();
00689       if ( parent->isSystemFolder() ) {
00690         QStringList remainder(parts);
00691         remainder.pop_front();
00692         remainder.pop_front();
00693         if ( dimapAccountCount() > 1 ) {
00694           // Fix kolab issue 2531 folder->storage() )->account() can be null
00695           if( folder->storage() && static_cast<const KMFolderCachedImap*>( folder->storage() )->account() ) {
00696           label = i18n( "My %1 (%2)")
00697               .arg( remainder.join( QString::fromLatin1("/") ),
00698                     static_cast<const KMFolderCachedImap*>( folder->storage() )->account()->name() );
00699           } else {
00700             label = i18n("My %1")
00701               .arg( remainder.join( QString::fromLatin1("/") ) );
00702           }
00703         } else {
00704           label = i18n("My %1")
00705               .arg( remainder.join( QString::fromLatin1("/") ) );
00706         }
00707         break;
00708       }
00709     }
00710     return label;
00711 }
00712 
00713 /* list all available subresources */
00714 QValueList<KMailICalIfaceImpl::SubResource> KMailICalIfaceImpl::subresourcesKolab( const QString& contentsType )
00715 {
00716   QValueList<SubResource> subResources;
00717 
00718   // Add the default one
00719   KMFolder* f = folderFromType( contentsType, QString::null );
00720   if ( f ) {
00721     subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
00722                                       f->isWritable(), folderIsAlarmRelevant( f ) ) );
00723     kdDebug(5006) << "Adding(1) folder " << f->location() << "    " <<
00724       ( !f->isWritable() ? "readonly" : "" ) << endl;
00725   }
00726 
00727   // get the extra ones
00728   const KMail::FolderContentsType t = folderContentsType( contentsType );
00729   QDictIterator<ExtraFolder> it( mExtraFolders );
00730   for ( ; it.current(); ++it ){
00731     f = it.current()->folder;
00732     if ( f && f->storage()->contentsType() == t ) {
00733       subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
00734                                         f->isWritable(), folderIsAlarmRelevant( f ) ) );
00735       kdDebug(5006) << "Adding(2) folder " << f->location() << "     " <<
00736               ( !f->isWritable() ? "readonly" : "" ) << endl;
00737     }
00738   }
00739 
00740   if ( subResources.isEmpty() )
00741     kdDebug(5006) << "subresourcesKolab: No folder found for " << contentsType << endl;
00742   return subResources;
00743 }
00744 
00745 bool KMailICalIfaceImpl::triggerSync( const QString& contentsType )
00746 {
00747   kdDebug(5006) << k_funcinfo << endl;
00748   QValueList<KMailICalIfaceImpl::SubResource> folderList = subresourcesKolab( contentsType );
00749   for ( QValueList<KMailICalIfaceImpl::SubResource>::const_iterator it( folderList.begin() ),
00750                                                                     end( folderList.end() );
00751         it != end ; ++it ) {
00752     KMFolder * const f = findResourceFolder( (*it).location );
00753     if ( !f ) continue;
00754     if ( f->folderType() == KMFolderTypeImap || f->folderType() == KMFolderTypeCachedImap ) {
00755       if ( !kmkernel->askToGoOnline() ) {
00756         return false;
00757       }
00758     }
00759 
00760     if ( f->folderType() == KMFolderTypeImap ) {
00761       KMFolderImap *imap = static_cast<KMFolderImap*>( f->storage() );
00762       imap->getAndCheckFolder();
00763     } else if ( f->folderType() == KMFolderTypeCachedImap ) {
00764       KMFolderCachedImap* cached = static_cast<KMFolderCachedImap*>( f->storage() );
00765       if ( cached->account() ) {
00766         cached->account()->processNewMailInFolder( f );
00767       }
00768     }
00769   }
00770   return true;
00771 }
00772 
00773 /* Used by the resource to query whether folders are writable. */
00774 bool KMailICalIfaceImpl::isWritableFolder( const QString& type,
00775                                            const QString& resource )
00776 {
00777   KMFolder* f = folderFromType( type, resource );
00778   if ( !f )
00779     // Definitely not writable
00780     return false;
00781 
00782   return f->isWritable();
00783 }
00784 
00785 /* Used by the resource to query the storage format of the folder. */
00786 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( const QString& resource )
00787 {
00788   StorageFormat format;
00789   KMFolder* f = findResourceFolder( resource );
00790   if ( f )
00791     format = storageFormat( f );
00792   else
00793     format = globalStorageFormat();
00794   return format;
00795 }
00796 
00811 Q_UINT32 KMailICalIfaceImpl::update( const QString& resource,
00812                                      Q_UINT32 sernum,
00813                                      const QString& subject,
00814                                      const QString& plainTextBody,
00815                                      const QMap<QCString, QString>& customHeaders,
00816                                      const QStringList& attachmentURLs,
00817                                      const QStringList& attachmentMimetypes,
00818                                      const QStringList& attachmentNames,
00819                                      const QStringList& deletedAttachments )
00820 {
00821   Q_UINT32 rc = 0;
00822 
00823    if( !mUseResourceIMAP )
00824     return rc;
00825 
00826   Q_ASSERT( !resource.isEmpty() );
00827 
00828   kdDebug(5006) << "KMailICalIfaceImpl::update( " << resource << ", " << sernum << " )\n";
00829   kdDebug(5006) << attachmentURLs << "\n";
00830   kdDebug(5006) << attachmentMimetypes << "\n";
00831   kdDebug(5006) << attachmentNames << "\n";
00832   kdDebug(5006) << "deleted attachments:" << deletedAttachments << "\n";
00833 
00834   // Find the folder
00835   KMFolder* f = findResourceFolder( resource );
00836   if( !f ) {
00837     kdError(5006) << "update(" << resource << ") : Not an IMAP resource folder" << endl;
00838     return rc;
00839   }
00840 
00841   f->open( "ifaceupdate" );
00842 
00843   KMMessage* msg = 0;
00844   if ( sernum != 0 ) {
00845     msg = findMessageBySerNum( sernum, f );
00846     if ( !msg ) return 0;
00847     // Message found - make a copy and update it:
00848     KMMessage* newMsg = new KMMessage( *msg );
00849     newMsg->setSubject( subject );
00850     QMap<QCString, QString>::ConstIterator ith = customHeaders.begin();
00851     const QMap<QCString, QString>::ConstIterator ithEnd = customHeaders.begin();
00852     for ( ; ith != ithEnd ; ++ith )
00853       newMsg->setHeaderField( ith.key(), ith.data() );
00854     newMsg->setParent( 0 ); // workaround strange line in KMMsgBase::assign. newMsg is not in any folder yet.
00855     // Note that plainTextBody isn't used in this branch. We assume it's still valid from when the mail was created.
00856 
00857     // Delete some attachments according to list
00858     for( QStringList::ConstIterator it = deletedAttachments.begin();
00859          it != deletedAttachments.end();
00860          ++it ){
00861       if( !deleteAttachment( *newMsg, *it ) ){
00862         // Note: It is _not_ an error if an attachment was already deleted.
00863       }
00864     }
00865 
00866     const KMail::FolderContentsType t = f->storage()->contentsType();
00867     const QCString type = msg->typeStr();
00868     const QCString subtype = msg->subtypeStr();
00869     const bool messageWasIcalVcardFormat = ( type.lower() == "text" &&
00870         ( subtype.lower() == "calendar" || subtype.lower() == "x-vcard" ) );
00871 
00872     if ( storageFormat( f ) == StorageIcalVcard ) {
00873       //kdDebug(5006) << k_funcinfo << " StorageFormatIcalVcard " << endl;
00874       if ( !messageWasIcalVcardFormat ) {
00875         setIcalVcardContentTypeHeader( newMsg, t, f );
00876       }
00877       newMsg->setBodyEncoded( plainTextBody.utf8() );
00878     } else if ( storageFormat( f ) == StorageXML ) {
00879       if ( messageWasIcalVcardFormat ) {
00880         // this was originally an ical event, but the folder changed to xml,
00881         // convert
00882        setXMLContentTypeHeader( newMsg, plainTextBody );
00883       }
00884       //kdDebug(5006) << k_funcinfo << " StorageFormatXML " << endl;
00885       // Add all attachments by reading them from their temp. files
00886       QStringList::ConstIterator iturl = attachmentURLs.begin();
00887       QStringList::ConstIterator itmime = attachmentMimetypes.begin();
00888       QStringList::ConstIterator itname = attachmentNames.begin();
00889       for( ;
00890           iturl != attachmentURLs.end()
00891           && itmime != attachmentMimetypes.end()
00892           && itname != attachmentNames.end();
00893           ++iturl, ++itname, ++itmime ){
00894         bool byname = !(*itmime).startsWith( "application/x-vnd.kolab." );
00895         if( !updateAttachment( *newMsg, *iturl, *itname, *itmime, byname ) ){
00896           kdDebug(5006) << "Attachment error, can not update attachment " << *iturl << endl;
00897           break;
00898         }
00899       }
00900     }
00901 
00902     //debugBodyParts( "in update, before cleanup", *newMsg );
00903 
00904     // This is necessary for the headers to be readable later on
00905     newMsg->cleanupHeader();
00906 
00907     //debugBodyParts( "in update, after cleanup", *newMsg );
00908 
00909     deleteMsg( msg );
00910     if ( f->addMsg( newMsg ) == 0 ) {
00911       // Message stored
00912       rc = newMsg->getMsgSerNum();
00913       kdDebug(5006) << "forget about " << sernum << ", it's " << rc << " now" << endl;
00914     }
00915     addFolderChange( f, Contents );
00916     syncFolder( f );
00917   } else {
00918     // Message not found - store it newly
00919     rc = addIncidenceKolab( *f, subject, plainTextBody, customHeaders,
00920                             attachmentURLs,
00921                             attachmentNames,
00922                             attachmentMimetypes );
00923   }
00924 
00925   f->close("ifaceupdate");
00926   return rc;
00927 }
00928 
00929 KURL KMailICalIfaceImpl::getAttachment( const QString& resource,
00930                                         Q_UINT32 sernum,
00931                                         const QString& filename )
00932 {
00933   // This finds the attachment with the filename, saves it to a
00934   // temp file and returns a URL to it. It's up to the resource
00935   // to delete the tmp file later.
00936   if( !mUseResourceIMAP )
00937     return KURL();
00938 
00939   kdDebug(5006) << "KMailICalIfaceImpl::getAttachment( "
00940                 << resource << ", " << sernum << ", " << filename << " )\n";
00941 
00942   // Find the folder
00943   KMFolder* f = findResourceFolder( resource );
00944   if( !f ) {
00945     kdError(5006) << "getAttachment(" << resource << ") : Not an IMAP resource folder" << endl;
00946     return KURL();
00947   }
00948   if ( storageFormat( f ) != StorageXML ) {
00949     kdError(5006) << "getAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
00950     return KURL();
00951   }
00952 
00953   KURL url;
00954 
00955   bool bOK = false;
00956   bool quiet = mResourceQuiet;
00957   mResourceQuiet = true;
00958 
00959   KMMessage* msg = findMessageBySerNum( sernum, f );
00960   if( msg ) {
00961     // Message found - look for the attachment:
00962 
00963     DwBodyPart* part = findBodyPart( *msg, filename );
00964     if ( part ) {
00965       // Save the contents of the attachment.
00966       KMMessagePart aPart;
00967       msg->bodyPart( part, &aPart );
00968       QByteArray rawData( aPart.bodyDecodedBinary() );
00969 
00970       KTempFile file;
00971       file.file()->writeBlock( rawData.data(), rawData.size() );
00972 
00973       url.setPath( file.name() );
00974 
00975       bOK = true;
00976     }
00977 
00978     if( !bOK ){
00979       kdDebug(5006) << "Attachment " << filename << " not found." << endl;
00980     }
00981   }else{
00982     kdDebug(5006) << "Message not found." << endl;
00983   }
00984 
00985   mResourceQuiet = quiet;
00986   return url;
00987 }
00988 
00989 QString KMailICalIfaceImpl::attachmentMimetype( const QString & resource,
00990                                                 Q_UINT32 sernum,
00991                                                 const QString & filename )
00992 {
00993   if( !mUseResourceIMAP )
00994     return QString();
00995   KMFolder* f = findResourceFolder( resource );
00996   if( !f || storageFormat( f ) != StorageXML ) {
00997     kdError(5006) << "attachmentMimetype(" << resource << ") : Wrong folder" << endl;
00998     return QString();
00999   }
01000 
01001   KMMessage* msg = findMessageBySerNum( sernum, f );
01002   if( msg ) {
01003     // Message found - look for the attachment:
01004     DwBodyPart* part = findBodyPart( *msg, filename );
01005     if ( part ) {
01006       KMMessagePart kmPart;
01007       msg->bodyPart( part, &kmPart );
01008       return QString( kmPart.typeStr() ) + "/" + QString( kmPart.subtypeStr() );
01009     } else {
01010       kdDebug(5006) << "Attachment " << filename << " not found." << endl;
01011     }
01012   } else {
01013     kdDebug(5006) << "Message not found." << endl;
01014   }
01015 
01016   return QString();
01017 }
01018 
01019 QStringList KMailICalIfaceImpl::listAttachments(const QString & resource, Q_UINT32 sernum)
01020 {
01021   QStringList rv;
01022   if( !mUseResourceIMAP )
01023     return rv;
01024 
01025   // Find the folder
01026   KMFolder* f = findResourceFolder( resource );
01027   if( !f ) {
01028     kdError(5006) << "listAttachments(" << resource << ") : Not an IMAP resource folder" << endl;
01029     return rv;
01030   }
01031   if ( storageFormat( f ) != StorageXML ) {
01032     kdError(5006) << "listAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
01033     return rv;
01034   }
01035 
01036   KMMessage* msg = findMessageBySerNum( sernum, f );
01037   if( msg ) {
01038     for ( DwBodyPart* part = msg->getFirstDwBodyPart(); part; part = part->Next() ) {
01039       if ( part->hasHeaders() ) {
01040         QString name;
01041         DwMediaType& contentType = part->Headers().ContentType();
01042         if ( QString( contentType.SubtypeStr().c_str() ).startsWith( "x-vnd.kolab." )
01043            || QString( contentType.SubtypeStr().c_str() ).contains( "tnef" ) )
01044           continue;
01045         if ( !part->Headers().ContentDisposition().Filename().empty() )
01046           name = part->Headers().ContentDisposition().Filename().c_str();
01047         else if ( !contentType.Name().empty() )
01048           name = contentType.Name().c_str();
01049         if ( !name.isEmpty() )
01050           rv.append( name );
01051       }
01052     }
01053   } else {
01054     kdDebug(5006) << "Message not found." << endl;
01055   }
01056 
01057   return rv;
01058 }
01059 
01060 
01061 // ============================================================================
01062 
01063 /* KMail part of the interface. These slots are connected to the resource
01064  * folders and inform us of folders or incidences in them changing, being
01065  * added or going away. */
01066 
01067 void KMailICalIfaceImpl::slotFolderRemoved( KMFolder* folder )
01068 {
01069   // pretend the folder just changed back to the mail type, which
01070   // does the right thing, namely remove resource
01071   folderContentsTypeChanged( folder, KMail::ContentsTypeMail );
01072   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01073   configGroup.deleteEntry( folder->idString() + "-storageFormat" );
01074   configGroup.deleteEntry( folder->idString() + "-changes" );
01075 }
01076 
01077 // KMail added a file to one of the groupware folders
01078 void KMailICalIfaceImpl::slotIncidenceAdded( KMFolder* folder,
01079                                              Q_UINT32 sernum )
01080 {
01081   if( mResourceQuiet || !mUseResourceIMAP )
01082     return;
01083 
01084 //  kdDebug(5006) << "KMailICalIfaceImpl::slotIncidenceAdded" << endl;
01085   QString type = folderContentsType( folder->storage()->contentsType() );
01086   if( type.isEmpty() ) {
01087     kdError(5006) << "Not an IMAP resource folder" << endl;
01088     return;
01089   }
01090   // Get the index of the mail
01091   int i = 0;
01092   KMFolder* aFolder = 0;
01093   KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
01094   assert( folder == aFolder );
01095 
01096   bool unget = !folder->isMessage( i );
01097   QString s;
01098   QString uid( "UID" );
01099   KMMessage *msg = folder->getMsg( i );
01100   if( !msg ) return;
01101   if( msg->isComplete() ) {
01102 
01103     bool ok = false;
01104     StorageFormat format = storageFormat( folder );
01105     switch( format ) {
01106       case StorageIcalVcard:
01107         // Read the iCal or vCard
01108         ok = vPartFoundAndDecoded( msg, s );
01109         if ( ok )
01110           vPartMicroParser( s, uid );
01111         break;
01112       case StorageXML:
01113         // Read the XML from the attachment with the given mimetype
01114         if ( kolabXMLFoundAndDecoded( *msg,
01115               folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
01116           uid = msg->subject();
01117           ok = true;
01118         }
01119         break;
01120     }
01121     if ( !ok ) {
01122       if ( unget )
01123         folder->unGetMsg( i );
01124       return;
01125     }
01126     const Q_UINT32 sernum = msg->getMsgSerNum();
01127     mUIDToSerNum.insert( uid, sernum );
01128 
01129     // tell the resource if we didn't trigger this ourselves
01130     if ( mInTransit.contains( uid ) ) {
01131       mInTransit.remove( uid );
01132     }
01133     incidenceAdded( type, folder->location(), sernum, format, s );
01134   } else {
01135     // go get the rest of it, then try again
01136     // TODO: Till, port me
01137     if ( unget ) mTheUnGetMes.insert( msg->getMsgSerNum(), true );
01138     FolderJob *job = msg->parent()->createJob( msg );
01139     connect( job, SIGNAL( messageRetrieved( KMMessage* ) ),
01140         this, SLOT( slotMessageRetrieved( KMMessage* ) ) );
01141     job->start();
01142     return;
01143   }
01144   if( unget ) folder->unGetMsg(i);
01145 }
01146 
01147 // KMail deleted a file
01148 void KMailICalIfaceImpl::slotIncidenceDeleted( KMFolder* folder,
01149                                                Q_UINT32 sernum )
01150 {
01151   if( mResourceQuiet || !mUseResourceIMAP )
01152     return;
01153 
01154   QString type = folderContentsType( folder->storage()->contentsType() );
01155   //kdDebug(5006) << folder << " " << type << " " << sernum << endl;
01156   if( !type.isEmpty() ) {
01157     // Get the index of the mail
01158     int i = 0;
01159     KMFolder* aFolder = 0;
01160     KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
01161     assert( folder == aFolder );
01162 
01163     // Read the iCal or vCard
01164     bool unget = !folder->isMessage( i );
01165     QString s;
01166     bool ok = false;
01167     KMMessage* msg = folder->getMsg( i );
01168     QString uid( "UID" );
01169     switch( storageFormat( folder ) ) {
01170     case StorageIcalVcard:
01171         if( vPartFoundAndDecoded( msg, s ) ) {
01172             vPartMicroParser( s, uid );
01173             ok = true;
01174         }
01175         break;
01176     case StorageXML:
01177         if ( kolabXMLFoundAndDecoded( *msg, folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
01178           uid = msg->subject();
01179           ok = true;
01180         }
01181         break;
01182     }
01183     if ( ok ) {
01184         kdDebug(5006) << "Emitting DCOP signal incidenceDeleted( "
01185                       << type << ", " << folder->location() << ", " << uid
01186                       << " )" << endl;
01187         incidenceDeleted( type, folder->location(), uid );
01188     }
01189     if( unget ) folder->unGetMsg(i);
01190   } else
01191     kdError(5006) << "Not a groupware folder" << endl;
01192 }
01193 
01194 // KMail orders a refresh
01195 void KMailICalIfaceImpl::slotRefresh( const QString& type )
01196 {
01197   if( mUseResourceIMAP ) {
01198     signalRefresh( type, QString::null /* PENDING(bo) folder->location() */ );
01199     kdDebug(5006) << "Emitting DCOP signal signalRefresh( " << type << " )" << endl;
01200   }
01201 }
01202 
01203 // This is among other things called when an expunge of a folder happens
01204 void KMailICalIfaceImpl::slotRefreshFolder( KMFolder* folder)
01205 {
01206   // TODO: The resources would of course be better off, if only this
01207   // folder would need refreshing. Currently it just orders a reload of
01208   // the type of the folder
01209   if( mUseResourceIMAP && folder ) {
01210     if( folder == mCalendar || folder == mContacts
01211         || folder == mNotes || folder == mTasks
01212         || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01213       // Refresh the folder of this type
01214       KMail::FolderContentsType ct = folder->storage()->contentsType();
01215       slotRefresh( s_folderContentsType[ct].contentsTypeStr );
01216     }
01217   }
01218 }
01219 
01220 /****************************
01221  * The folder and message stuff code
01222  */
01223 
01224 KMFolder* KMailICalIfaceImpl::folderFromType( const QString& type,
01225                                               const QString& folder )
01226 {
01227   if( mUseResourceIMAP ) {
01228     KMFolder* f = 0;
01229     if ( !folder.isEmpty() ) {
01230       f = extraFolder( type, folder );
01231       if ( f )
01232         return f;
01233     }
01234 
01235     if( type == "Calendar" ) f = mCalendar;
01236     else if( type == "Contact" ) f = mContacts;
01237     else if( type == "Note" ) f = mNotes;
01238     else if( type == "Task" || type == "Todo" ) f = mTasks;
01239     else if( type == "Journal" ) f = mJournals;
01240 
01241     if ( f && ( folder.isEmpty() || folder == f->location() ) )
01242       return f;
01243 
01244     kdError(5006) << "No folder ( " << type << ", " << folder << " )\n";
01245   }
01246 
01247   return 0;
01248 }
01249 
01250 
01251 // Returns true if folder is a resource folder. If the resource isn't enabled
01252 // this always returns false
01253 bool KMailICalIfaceImpl::isResourceFolder( KMFolder* folder ) const
01254 {
01255   return mUseResourceIMAP && folder &&
01256     ( isStandardResourceFolder( folder ) || mExtraFolders.find( folder->location() )!=0 );
01257 }
01258 
01259 bool KMailICalIfaceImpl::isStandardResourceFolder( KMFolder* folder ) const
01260 {
01261   return ( folder == mCalendar || folder == mTasks || folder == mJournals ||
01262            folder == mNotes || folder == mContacts );
01263 }
01264 
01265 bool KMailICalIfaceImpl::hideResourceFolder( KMFolder* folder ) const
01266 {
01267   return mHideFolders && isResourceFolder( folder );
01268 }
01269 
01270 bool KMailICalIfaceImpl::hideResourceAccountRoot( KMFolder* folder ) const
01271 {
01272   KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
01273   bool hide = dimapFolder && mHideFolders
01274        && (int)dimapFolder->account()->id() == GlobalSettings::self()->theIMAPResourceAccount()
01275        && GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount();
01276   return hide;
01277 
01278 }
01279 
01280 KFolderTreeItem::Type KMailICalIfaceImpl::folderType( KMFolder* folder ) const
01281 {
01282   if( mUseResourceIMAP && folder ) {
01283     if( folder == mCalendar || folder == mContacts
01284         || folder == mNotes || folder == mTasks
01285         || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01286       KMail::FolderContentsType ct = folder->storage()->contentsType();
01287       return s_folderContentsType[ct].treeItemType;
01288     }
01289   }
01290 
01291   return KFolderTreeItem::Other;
01292 }
01293 
01294 // Global tables of foldernames is different languages
01295 // For now: 0->English, 1->German, 2->French, 3->Dutch
01296 static QMap<KFolderTreeItem::Type,QString> folderNames[4];
01297 QString KMailICalIfaceImpl::folderName( KFolderTreeItem::Type type, int language ) const
01298 {
01299   // With the XML storage, folders are always (internally) named in English
01300   if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
01301     language = 0;
01302 
01303   static bool folderNamesSet = false;
01304   if( !folderNamesSet ) {
01305     folderNamesSet = true;
01306     /* NOTE: If you add something here, you also need to update
01307        GroupwarePage in configuredialog.cpp */
01308 
01309     // English
01310     folderNames[0][KFolderTreeItem::Calendar] = QString::fromLatin1("Calendar");
01311     folderNames[0][KFolderTreeItem::Tasks] = QString::fromLatin1("Tasks");
01312     folderNames[0][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01313     folderNames[0][KFolderTreeItem::Contacts] = QString::fromLatin1("Contacts");
01314     folderNames[0][KFolderTreeItem::Notes] = QString::fromLatin1("Notes");
01315 
01316     // German
01317     folderNames[1][KFolderTreeItem::Calendar] = QString::fromLatin1("Kalender");
01318     folderNames[1][KFolderTreeItem::Tasks] = QString::fromLatin1("Aufgaben");
01319     folderNames[1][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01320     folderNames[1][KFolderTreeItem::Contacts] = QString::fromLatin1("Kontakte");
01321     folderNames[1][KFolderTreeItem::Notes] = QString::fromLatin1("Notizen");
01322 
01323     // French
01324     folderNames[2][KFolderTreeItem::Calendar] = QString::fromLatin1("Calendrier");
01325     // Tasks = Tâches (â == 0xE2 in latin1)
01326     folderNames[2][KFolderTreeItem::Tasks] = QString::fromLatin1("T\342ches");
01327     folderNames[2][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01328     folderNames[2][KFolderTreeItem::Contacts] = QString::fromLatin1("Contacts");
01329     folderNames[2][KFolderTreeItem::Notes] = QString::fromLatin1("Notes");
01330 
01331     // Dutch
01332     folderNames[3][KFolderTreeItem::Calendar] = QString::fromLatin1("Agenda");
01333     folderNames[3][KFolderTreeItem::Tasks] = QString::fromLatin1("Taken");
01334     folderNames[3][KFolderTreeItem::Journals] = QString::fromLatin1("Logboek");
01335     folderNames[3][KFolderTreeItem::Contacts] = QString::fromLatin1("Contactpersonen");
01336     folderNames[3][KFolderTreeItem::Notes] = QString::fromLatin1("Notities");
01337   }
01338 
01339   if( language < 0 || language > 3 ) {
01340     return folderNames[mFolderLanguage][type];
01341   }
01342   else {
01343     return folderNames[language][type];
01344   }
01345 }
01346 
01347 
01348 // Find message matching a given UID
01349 KMMessage *KMailICalIfaceImpl::findMessageByUID( const QString& uid, KMFolder* folder )
01350 {
01351   if( !folder || !mUIDToSerNum.contains( uid ) ) return 0;
01352   int i;
01353   KMFolder *aFolder;
01354   KMMsgDict::instance()->getLocation( mUIDToSerNum[uid], &aFolder, &i );
01355   Q_ASSERT( aFolder == folder );
01356   return folder->getMsg( i );
01357 }
01358 
01359 // Find message matching a given serial number
01360 KMMessage *KMailICalIfaceImpl::findMessageBySerNum( Q_UINT32 serNum, KMFolder* folder )
01361 {
01362   if( !folder ) return 0;
01363 
01364   KMMessage *message = 0;
01365   KMFolder* aFolder = 0;
01366   int index;
01367   KMMsgDict::instance()->getLocation( serNum, &aFolder, &index );
01368 
01369   if( aFolder && aFolder != folder ) {
01370     kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) found it in folder " << aFolder->location() << ", expected " << folder->location() << endl;
01371   } else {
01372     if( aFolder )
01373       message = aFolder->getMsg( index );
01374     if (!message)
01375       kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) invalid serial number\n" << endl;
01376   }
01377   return message;
01378 }
01379 
01380 void KMailICalIfaceImpl::deleteMsg( KMMessage *msg )
01381 {
01382   if( !msg ) return;
01383   // Commands are now delayed; can't use that anymore, we need immediate deletion
01384   //( new KMDeleteMsgCommand( msg->parent(), msg ) )->start();
01385   KMFolder *srcFolder = msg->parent();
01386   int idx = srcFolder->find(msg);
01387   assert(idx != -1);
01388   // kill existing jobs since we are about to delete the message
01389   srcFolder->ignoreJobsForMessage( msg );
01390   if ( !msg->transferInProgress() ) {
01391     srcFolder->removeMsg(idx);
01392     delete msg;
01393   } else {
01394     kdDebug(5006) << k_funcinfo << "Message cannot be deleted now because it is currently in use " << msg << endl;
01395     msg->deleteWhenUnused();
01396   }
01397   addFolderChange( srcFolder, Contents );
01398 }
01399 
01400 void KMailICalIfaceImpl::folderContentsTypeChanged( KMFolder* folder,
01401                                                     KMail::FolderContentsType contentsType )
01402 {
01403   if ( !mUseResourceIMAP )
01404     return;
01405 //  kdDebug(5006) << "folderContentsTypeChanged( " << folder->name()
01406 //                << ", " << contentsType << ")\n";
01407 
01408   // The builtins can't change type
01409   if ( isStandardResourceFolder( folder ) )
01410     return;
01411 
01412   // Check if already know that 'extra folder'
01413   const QString location = folder->location();
01414   ExtraFolder* ef = mExtraFolders.find( location );
01415   if ( ef && ef->folder ) {
01416     // Notify that the old folder resource is no longer available
01417     subresourceDeleted(folderContentsType( folder->storage()->contentsType() ), location );
01418 
01419     if ( contentsType == KMail::ContentsTypeMail ) {
01420       // Delete the old entry, stop listening and stop here
01421       mExtraFolders.remove( location );
01422       folder->disconnect( this );
01423       return;
01424     }
01425     // So the type changed to another groupware type, ok.
01426   } else {
01427     if ( ef && !ef->folder ) // deleted folder, clean up
01428       mExtraFolders.remove( location );
01429     if ( contentsType == KMail::ContentsTypeMail )
01430         return;
01431 
01432     //kdDebug(5006) << "registering " << location << " as extra folder" << endl;
01433     // Make a new entry for the list
01434     ef = new ExtraFolder( folder );
01435     mExtraFolders.insert( location, ef );
01436 
01437     FolderInfo info = readFolderInfo( folder );
01438     mFolderInfoMap.insert( folder, info );
01439 
01440     // Adjust the folder names of all foo.default folders.
01441     // German users will get Kalender as the name of all default Calendar folders,
01442     // including their own, so that the default calendar folder of their Japanese
01443     // coworker appears as /user/hirohito/Kalender, although Hirohito sees his folder
01444     // in Japanese. On the server the folders are always in English.
01445     if ( folder->folderType() == KMFolderTypeCachedImap ) {
01446       QString annotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
01447       kdDebug(5006) << "folderContentsTypeChanged: " << folder->name() << " has annotation " << annotation << endl;
01448       if ( annotation == QString( s_folderContentsType[contentsType].annotation ) + ".default" )
01449         folder->setLabel( localizedDefaultFolderName( contentsType ) );
01450     }
01451 
01452     connectFolder( folder );
01453   }
01454   // Tell about the new resource
01455   subresourceAdded( folderContentsType( contentsType ), location, subresourceLabelForPresentation(folder),
01456                     folder->isWritable(), folderIsAlarmRelevant( folder ) );
01457 }
01458 
01459 KMFolder* KMailICalIfaceImpl::extraFolder( const QString& type,
01460                                            const QString& folder )
01461 {
01462   // If an extra folder exists that matches the type and folder location,
01463   // use that
01464   int t = folderContentsType( type );
01465   if ( t < 1 || t > 5 )
01466     return 0;
01467 
01468   ExtraFolder* ef = mExtraFolders.find( folder );
01469   if ( ef && ef->folder && ef->folder->storage()->contentsType() == t )
01470     return ef->folder;
01471 
01472   return 0;
01473 }
01474 
01475 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( KMFolder* folder ) const
01476 {
01477   FolderInfoMap::ConstIterator it = mFolderInfoMap.find( folder );
01478   if ( it != mFolderInfoMap.end() )
01479     return (*it).mStorageFormat;
01480   return globalStorageFormat();
01481 }
01482 
01483 void KMailICalIfaceImpl::setStorageFormat( KMFolder* folder, StorageFormat format )
01484 {
01485   FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01486   if ( it != mFolderInfoMap.end() ) {
01487     (*it).mStorageFormat = format;
01488   } else {
01489     FolderInfo info( format, NoChange );
01490     mFolderInfoMap.insert( folder, info );
01491   }
01492   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01493   configGroup.writeEntry( folder->idString() + "-storageFormat",
01494                           format == StorageXML ? "xml" : "icalvcard" );
01495 }
01496 
01497 void KMailICalIfaceImpl::addFolderChange( KMFolder* folder, FolderChanges changes )
01498 {
01499   FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01500   if ( it != mFolderInfoMap.end() ) {
01501     (*it).mChanges = static_cast<FolderChanges>( (*it).mChanges | changes );
01502   } else { // Otherwise, well, it's a folder we don't care about.
01503     kdDebug(5006) << "addFolderChange: nothing known about folder " << folder->location() << endl;
01504   }
01505   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01506   configGroup.writeEntry( folder->idString() + "-changes", (*it).mChanges );
01507 }
01508 
01509 KMailICalIfaceImpl::FolderInfo KMailICalIfaceImpl::readFolderInfo( const KMFolder * const folder ) const
01510 {
01511   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01512   QString str = configGroup.readEntry( folder->idString() + "-storageFormat", "unset" );
01513   FolderInfo info;
01514   if ( str == "unset" ) {
01515     info.mStorageFormat = globalStorageFormat();
01516     configGroup.writeEntry( folder->idString() + "-storageFormat",
01517                             info.mStorageFormat == StorageXML ? "xml" : "icalvcard" );
01518   } else {
01519     info.mStorageFormat = ( str == "xml" ) ? StorageXML : StorageIcalVcard;
01520   }
01521   info.mChanges = (FolderChanges) configGroup.readNumEntry( folder->idString() + "-changes" );
01522   return info;
01523 }
01524 
01525 
01526 void KMailICalIfaceImpl::folderSynced( KMFolder* folder, const KURL& folderURL )
01527 {
01528   FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01529   if ( it != mFolderInfoMap.end() && (*it).mChanges ) {
01530     handleFolderSynced( folder, folderURL, (*it).mChanges );
01531     (*it).mChanges = NoChange;
01532   }
01533 }
01534 
01535 void KMailICalIfaceImpl::handleFolderSynced( KMFolder* folder,
01536                                              const KURL& folderURL,
01537                                              int _changes )
01538 {
01539   // This is done here instead of in the resource, because
01540   // there could be 0, 1, or N kolab resources at this point.
01541   // We can hack the N case, but not the 0 case.
01542   // So the idea of a DCOP signal for this wouldn't work.
01543   if ( ( _changes & KMailICalIface::Contents ) ||
01544        ( _changes & KMailICalIface::ACL ) ) {
01545     if ( storageFormat( folder ) == StorageXML && folder->storage()->contentsType() == KMail::ContentsTypeCalendar )
01546       triggerKolabFreeBusy( folderURL );
01547   }
01548 }
01549 
01550 void KMailICalIfaceImpl::folderDeletedOnServer( const KURL& folderURL )
01551 {
01552   triggerKolabFreeBusy( folderURL );
01553 }
01554 
01555 void KMailICalIfaceImpl::triggerKolabFreeBusy( const KURL& folderURL )
01556 {
01557   /* Steffen said: you must issue an authenticated HTTP GET request to
01558      https://kolabserver/freebusy/trigger/user@domain/Folder/NestedFolder.pfb
01559      (replace .pfb with .xpfb for extended fb lists). */
01560   KURL httpURL( folderURL );
01561   // Keep username ("user@domain"), pass, and host from the imap url
01562   httpURL.setProtocol( "https" );
01563   httpURL.setPort( 0 ); // remove imap port
01564 
01565   // IMAP path is either /INBOX/<path> or /user/someone/<path>
01566   QString path = folderURL.path( -1 );
01567   Q_ASSERT( path.startsWith( "/" ) );
01568   int secondSlash = path.find( '/', 1 );
01569   if ( secondSlash == -1 ) {
01570     kdWarning() << "KCal::ResourceKolab::fromKMailFolderSynced path is too short: " << path << endl;
01571     return;
01572   }
01573   if ( path.startsWith( "/INBOX/", false ) ) {
01574     // If INBOX, replace it with the username (which is user@domain)
01575     path = path.mid( secondSlash );
01576     path.prepend( folderURL.user() );
01577   } else {
01578     // If user, just remove it. So we keep the IMAP-returned username.
01579     // This assumes it's a known user on the same domain.
01580     path = path.mid( secondSlash );
01581   }
01582 
01583   httpURL.setPath( "/freebusy/trigger/" + path + ".pfb" );
01584   httpURL.setQuery( QString::null );
01585   // Ensure that we encode everything with UTF8
01586   httpURL = KURL( httpURL.url(0,106), 106 );
01587   kdDebug() << "Triggering PFB update for " << folderURL << " : getting " << httpURL << endl;
01588   // "Fire and forget". No need for error handling, nor for explicit deletion.
01589   // Maybe we should try to prevent launching it if it's already running (for this URL) though.
01590   /*KIO::Job* job =*/ KIO::get( httpURL, false, false /*no progress info*/ );
01591 }
01592 
01593 void KMailICalIfaceImpl::slotFolderPropertiesChanged( KMFolder* folder )
01594 {
01595   if ( isResourceFolder( folder ) ) {
01596     const QString location = folder->location();
01597     const QString contentsTypeStr = folderContentsType( folder->storage()->contentsType() );
01598     subresourceDeleted( contentsTypeStr, location );
01599 
01600     subresourceAdded( contentsTypeStr, location, subresourceLabelForPresentation( folder ),
01601                       folder->isWritable(), folderIsAlarmRelevant( folder ) );
01602   }
01603 }
01604 
01605 // Must only be connected to a signal from KMFolder!
01606 void KMailICalIfaceImpl::slotFolderRenamed()
01607 {
01608   const KMFolder* folder = static_cast<const KMFolder *>( sender() );
01609   slotFolderPropertiesChanged( const_cast<KMFolder*>( folder ) );
01610 }
01611 
01612 void KMailICalIfaceImpl::slotFolderLocationChanged( const QString &oldLocation,
01613                                                     const QString &newLocation )
01614 {
01615   KMFolder *folder = findResourceFolder( oldLocation );
01616   ExtraFolder* ef = mExtraFolders.find( oldLocation );
01617   if ( ef ) {
01618     // reuse the ExtraFolder entry, but adjust the key
01619     mExtraFolders.setAutoDelete( false );
01620     mExtraFolders.remove( oldLocation );
01621     mExtraFolders.setAutoDelete( true );
01622     mExtraFolders.insert( newLocation, ef );
01623   }
01624   if (  folder )
01625     subresourceDeleted( folderContentsType(  folder->storage()->contentsType() ), oldLocation );
01626 
01627 }
01628 
01629 KMFolder* KMailICalIfaceImpl::findResourceFolder( const QString& resource )
01630 {
01631   // Try the standard folders
01632   if( mCalendar && mCalendar->location() == resource )
01633     return mCalendar;
01634   if ( mContacts && mContacts->location() == resource )
01635     return mContacts;
01636   if ( mNotes && mNotes->location() == resource )
01637     return mNotes;
01638   if ( mTasks && mTasks->location() == resource )
01639     return mTasks;
01640   if ( mJournals && mJournals->location() == resource )
01641     return mJournals;
01642 
01643   // No luck. Try the extrafolders
01644   ExtraFolder* ef = mExtraFolders.find( resource );
01645   if ( ef )
01646     return ef->folder;
01647 
01648   // No luck at all
01649   return 0;
01650 }
01651 
01652 void KMailICalIfaceImpl::changeResourceUIName( const QString &folderPath, const QString &newName )
01653 {
01654   kdDebug() << "Folder path " << folderPath << endl;
01655   KMFolder *f = findResourceFolder( folderPath );
01656   if ( f ) {
01657     KMailICalIfaceImpl::getResourceMap()->insert( folderPath, newName );
01658     kmkernel->folderMgr()->renameFolder( f, newName );
01659     KConfigGroup configGroup( kmkernel->config(), "Resource UINames" );
01660     configGroup.writeEntry( folderPath, newName );
01661   }
01662 }
01663 
01664 // Builds a folder list from the dimap and the local folder list.
01665 static void createFolderList( QStringList &folderNames, QValueList<QGuardedPtr<KMFolder> > &folderList )
01666 {
01667   QStringList dimapFolderNames;
01668   QStringList localFolderNames;
01669   QValueList<QGuardedPtr<KMFolder> > dimapFolderList;
01670   QValueList<QGuardedPtr<KMFolder> > localFolderList;
01671   kmkernel->dimapFolderMgr()->createFolderList( &dimapFolderNames, &dimapFolderList );
01672   kmkernel->folderMgr()->createFolderList( &localFolderNames, &localFolderList );
01673   folderNames += dimapFolderNames;
01674   folderNames += localFolderNames;
01675   folderList += dimapFolderList;
01676   folderList += localFolderList;
01677 }
01678 
01679 /****************************
01680  * The config stuff
01681  */
01682 
01683 void KMailICalIfaceImpl::readConfig()
01684 {
01685   bool enabled = GlobalSettings::self()->theIMAPResourceEnabled() &&
01686                  ( GlobalSettings::self()->theIMAPResourceAccount() != 0 );
01687 
01688   if( !enabled ) {
01689     if( mUseResourceIMAP == true ) {
01690       // Shutting down
01691       mUseResourceIMAP = false;
01692       cleanup();
01693       reloadFolderTree();
01694     }
01695     return;
01696   }
01697   mUseResourceIMAP = enabled;
01698 
01699   // Read remaining options
01700   const bool hideFolders = GlobalSettings::self()->hideGroupwareFolders();
01701   QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01702 
01703   // Find the folder parent
01704   KMFolderDir* folderParentDir;
01705   KMFolderType folderType;
01706   KMFolder* folderParent = kmkernel->findFolderById( parentName );
01707   if( folderParent == 0 ) {
01708     // Parent folder not found. It was probably deleted. The user will have to
01709     // configure things again.
01710     kdDebug(5006) << "Groupware folder " << parentName << " not found. Groupware functionality disabled" << endl;
01711     // Or maybe the inbox simply wasn't created on the first startup
01712     KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01713     Q_ASSERT( account );
01714     if ( account ) {
01715       // just in case we were connected already
01716       disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01717                this, SLOT( slotCheckDone() ) );
01718       connect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01719                this, SLOT( slotCheckDone() ) );
01720     }
01721     mUseResourceIMAP = false;
01722     // We can't really call cleanup(), if those folders were completely deleted.
01723     mCalendar = 0;
01724     mTasks    = 0;
01725     mJournals = 0;
01726     mContacts = 0;
01727     mNotes    = 0;
01728     return;
01729   } else {
01730     folderParentDir = folderParent->createChildFolder();
01731     folderType = folderParent->folderType();
01732   }
01733 
01734   KMAcctCachedImap::GroupwareType groupwareType = dynamic_cast<KMFolderCachedImap *>( folderParent->storage() )->account()->groupwareType();
01735 
01736   if ( groupwareType == KMAcctCachedImap::GroupwareKolab ) {
01737     // Make sure the folder parent has the subdirs
01738     // Globally there are 3 cases: nothing found, some stuff found by type/name heuristics, or everything found OK
01739     bool noneFound = true;
01740     bool mustFix = false; // true when at least one was found by heuristics
01741     QValueVector<StandardFolderSearchResult> results( KMail::ContentsTypeLast + 1 );
01742     for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01743       if ( i != KMail::ContentsTypeMail ) {
01744         results[i] = findStandardResourceFolder( folderParentDir, static_cast<KMail::FolderContentsType>(i) );
01745         if ( results[i].found == StandardFolderSearchResult::FoundAndStandard )
01746           noneFound = false;
01747         else if ( results[i].found == StandardFolderSearchResult::FoundByType ||
01748                   results[i].found == StandardFolderSearchResult::FoundByName ) {
01749           mustFix = true;
01750           noneFound = false;
01751         } else // NotFound
01752           mustFix = true;
01753       }
01754     }
01755 
01756     // Check if something changed
01757     if( mUseResourceIMAP && !noneFound && !mustFix && mFolderParentDir == folderParentDir
01758         && mFolderType == folderType ) {
01759       // Nothing changed
01760       if ( hideFolders != mHideFolders ) {
01761         // Well, the folder hiding has changed
01762         mHideFolders = hideFolders;
01763         reloadFolderTree();
01764       }
01765       return;
01766     }
01767 
01768     if( noneFound || mustFix ) {
01769       QString msg;
01770       QString parentFolderName = folderParent != 0 ? folderParent->name() : folderParentDir->name();
01771       if ( noneFound ) {
01772         // No subfolder was found, so ask if we can make them
01773         msg = i18n("KMail will now create the required groupware folders"
01774                    " as subfolders of %1; if you do not want this, cancel"
01775                    " and the IMAP resource will be disabled").arg(parentFolderName);
01776       } else {
01777         // Some subfolders were found, be more precise
01778         QString operations = "<ul>";
01779         for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01780           if ( i != KMail::ContentsTypeMail ) {
01781             QString typeName = localizedDefaultFolderName( static_cast<KMail::FolderContentsType>( i ) );
01782             if ( results[i].found == StandardFolderSearchResult::NotFound )
01783               operations += "<li>" + i18n( "%1: no folder found. It will be created." ).arg( typeName ) + "</li>";
01784             else if ( results[i].found == StandardFolderSearchResult::FoundByType || results[i].found == StandardFolderSearchResult::FoundByName )
01785               operations += "<li>" + i18n( "%1: found folder %2. It will be set as the main groupware folder." ).
01786                             arg( typeName ).arg( results[i].folder->label() ) + "</li>";
01787           }
01788         }
01789         operations += "</ul>";
01790 
01791         msg = i18n("<qt>KMail found the following groupware folders in %1 and needs to perform the following operations: %2"
01792                    "<br>If you do not want this, cancel"
01793                    " and the IMAP resource will be disabled").arg(parentFolderName, operations);
01794 
01795       }
01796 
01797       if( KMessageBox::questionYesNo( 0, msg,
01798                                       i18n("Standard Groupware Folders"), KStdGuiItem::cont(), KStdGuiItem::cancel() ) == KMessageBox::No ) {
01799 
01800         GlobalSettings::self()->setTheIMAPResourceEnabled( false );
01801         mUseResourceIMAP = false;
01802         mFolderParentDir = 0;
01803         mFolderParent = 0;
01804         reloadFolderTree();
01805         return;
01806       }
01807     }
01808 
01809     // Make the new settings work
01810     mUseResourceIMAP = true;
01811     mFolderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
01812     if( mFolderLanguage > 3 ) mFolderLanguage = 0;
01813     mFolderParentDir = folderParentDir;
01814     mFolderParent = folderParent;
01815     mFolderType = folderType;
01816     mHideFolders = hideFolders;
01817 
01818     // Close the previous folders
01819     cleanup();
01820 
01821     // Set the new folders
01822     mCalendar = initFolder( KMail::ContentsTypeCalendar );
01823     mTasks    = initFolder( KMail::ContentsTypeTask );
01824     mJournals = initFolder( KMail::ContentsTypeJournal );
01825     mContacts = initFolder( KMail::ContentsTypeContact );
01826     mNotes    = initFolder( KMail::ContentsTypeNote );
01827 
01828     // Store final annotation (with .default) so that we won't ask again on next startup
01829     if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01830       static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01831     if ( mTasks->folderType() == KMFolderTypeCachedImap )
01832       static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01833     if ( mJournals->folderType() == KMFolderTypeCachedImap )
01834       static_cast<KMFolderCachedImap *>( mJournals->storage() )->updateAnnotationFolderType();
01835     if ( mContacts->folderType() == KMFolderTypeCachedImap )
01836       static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01837     if ( mNotes->folderType() == KMFolderTypeCachedImap )
01838       static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01839 
01840     kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
01841     kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
01842     kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
01843 
01844     // Find all extra folders
01845     QStringList folderNames;
01846     QValueList<QGuardedPtr<KMFolder> > folderList;
01847     createFolderList( folderNames, folderList );
01848     for( QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
01849          it != folderList.end(); ++it )
01850     {
01851       FolderStorage *storage = (*it)->storage();
01852       KMFolderCachedImap* dimapStorage = dynamic_cast<KMFolderCachedImap*>( storage );
01853       if ( storage && storage->contentsType() != 0 ) {
01854         if ( dimapStorage )
01855           dimapStorage->updateAnnotationFolderType();
01856         folderContentsTypeChanged( *it, storage->contentsType() );
01857       }
01858     }
01859 
01860     // If we just created them, they might have been registered as extra folders temporarily.
01861     // -> undo that.
01862     mExtraFolders.remove( mCalendar->location() );
01863     mExtraFolders.remove( mTasks->location() );
01864     mExtraFolders.remove( mJournals->location() );
01865     mExtraFolders.remove( mContacts->location() );
01866     mExtraFolders.remove( mNotes->location() );
01867 
01868     subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
01869     subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
01870     subresourceAdded( folderContentsType( KMail::ContentsTypeJournal ), mJournals->location(), mJournals->label(), true, false );
01871     subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
01872     subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
01873   } else if ( groupwareType == KMAcctCachedImap::GroupwareScalix ) {
01874     // Make the new settings work
01875     mUseResourceIMAP = true;
01876     mFolderParentDir = folderParentDir;
01877     mFolderParent = folderParent;
01878     mFolderType = folderType;
01879     mHideFolders = false;
01880 
01881     // Close the previous folders
01882     cleanup();
01883 
01884     // Set the new folders
01885     mCalendar = initScalixFolder( KMail::ContentsTypeCalendar );
01886     mTasks    = initScalixFolder( KMail::ContentsTypeTask );
01887     mJournals = 0;
01888     mContacts = initScalixFolder( KMail::ContentsTypeContact );
01889     mNotes    = initScalixFolder( KMail::ContentsTypeNote );
01890 
01891     // Store final annotation (with .default) so that we won't ask again on next startup
01892     if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01893       static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01894     if ( mTasks->folderType() == KMFolderTypeCachedImap )
01895       static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01896     if ( mContacts->folderType() == KMFolderTypeCachedImap )
01897       static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01898     if ( mNotes->folderType() == KMFolderTypeCachedImap )
01899       static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01900 
01901     // BEGIN TILL TODO The below only uses the dimap folder manager, which
01902     // will fail for all other folder types. Adjust.
01903 
01904     kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
01905     kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
01906     kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
01907 
01908     // Find all extra folders
01909     QStringList folderNames;
01910     QValueList<QGuardedPtr<KMFolder> > folderList;
01911     kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
01912     QValueList<QGuardedPtr<KMFolder> >::iterator it;
01913     for(it = folderList.begin(); it != folderList.end(); ++it)
01914     {
01915       FolderStorage *storage = (*it)->storage();
01916 
01917       if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
01918         KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
01919 
01920         const QString attributes = imapFolder->folderAttributes();
01921         if ( attributes.contains( "X-FolderClass" ) ) {
01922           if ( !attributes.contains( "X-SpecialFolder" ) || (*it)->location().contains( "@" ) ) {
01923             const Scalix::FolderAttributeParser parser( attributes );
01924             if ( !parser.folderClass().isEmpty() ) {
01925               FolderContentsType type = Scalix::Utils::scalixIdToContentsType( parser.folderClass() );
01926               imapFolder->setContentsType( type );
01927               folderContentsTypeChanged( *it, type );
01928             }
01929           }
01930         }
01931       }
01932     }
01933 
01934     // If we just created them, they might have been registered as extra folders temporarily.
01935     // -> undo that.
01936     mExtraFolders.remove( mCalendar->location() );
01937     mExtraFolders.remove( mTasks->location() );
01938     mExtraFolders.remove( mContacts->location() );
01939     mExtraFolders.remove( mNotes->location() );
01940 
01941     // END TILL TODO
01942 
01943     subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
01944     subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
01945     subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
01946     subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
01947   }
01948 
01949   KConfig *config = kmkernel->config();
01950   config->setGroup("Resource UINames");
01951   *KMailICalIfaceImpl::mSubResourceUINamesMap =  config->entryMap( "Resource UINames" );
01952 
01953   reloadFolderTree();
01954 }
01955 
01956 void KMailICalIfaceImpl::slotCheckDone()
01957 {
01958   QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01959   KMFolder* folderParent = kmkernel->findFolderById( parentName );
01960   //kdDebug(5006) << k_funcinfo << " folderParent=" << folderParent << endl;
01961   if ( folderParent )  // cool it exists now
01962   {
01963     KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01964     if ( account )
01965       disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01966                   this, SLOT( slotCheckDone() ) );
01967     readConfig();
01968   }
01969 }
01970 
01971 KMFolder* KMailICalIfaceImpl::initFolder( KMail::FolderContentsType contentsType )
01972 {
01973   // Figure out what type of folder this is supposed to be
01974   KMFolderType type = mFolderType;
01975   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
01976 
01977   KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
01978   //kdDebug(5006) << "KMailICalIfaceImpl::initFolder " << folderName( itemType ) << endl;
01979 
01980   // Find the folder
01981   StandardFolderSearchResult result = findStandardResourceFolder( mFolderParentDir, contentsType );
01982 
01983   // deal with multiple default groupware folders
01984   if ( result.folders.count() > 1 && result.found == StandardFolderSearchResult::FoundAndStandard ) {
01985     QStringList labels;
01986     for ( QValueList<KMFolder*>::ConstIterator it = result.folders.begin(); it != result.folders.end(); ++it )
01987       labels << (*it)->prettyURL();
01988     const QString selected = KInputDialog::getItem( i18n("Default folder"),
01989         i18n("There are multiple %1 default folders, please choose one:")
01990         .arg( localizedDefaultFolderName( contentsType ) ), labels );
01991     if ( !selected.isEmpty() )
01992       result.folder = result.folders[ labels.findIndex( selected ) ];
01993   }
01994 
01995   KMFolder* folder = result.folder;
01996 
01997   if ( !folder ) {
01998     // The folder isn't there yet - create it
01999     folder =
02000       mFolderParentDir->createFolder( localizedDefaultFolderName( contentsType ), false, type );
02001     if( mFolderType == KMFolderTypeImap ) {
02002       KMFolderImap* parentFolder = static_cast<KMFolderImap*>( mFolderParent->storage() );
02003       parentFolder->createFolder( localizedDefaultFolderName( contentsType ) );
02004       static_cast<KMFolderImap*>( folder->storage() )->setAccount( parentFolder->account() );
02005     }
02006     // Groupware folder created, use the global setting for storage format
02007     setStorageFormat( folder, globalStorageFormat() );
02008   } else {
02009     FolderInfo info = readFolderInfo( folder );
02010     mFolderInfoMap.insert( folder, info );
02011     //kdDebug(5006) << "Found existing folder type " << itemType << " : " << folder->location()  << endl;
02012   }
02013 
02014   if( folder->canAccess() != 0 ) {
02015     KMessageBox::sorry(0, i18n("You do not have read/write permission to your %1 folder.")
02016                        .arg( folderName( itemType ) ) );
02017     return 0;
02018   }
02019   folder->storage()->setContentsType( contentsType );
02020   folder->setSystemFolder( true );
02021   folder->storage()->writeConfig();
02022   folder->open("ifacefolder");
02023   connectFolder( folder );
02024   return folder;
02025 }
02026 
02027 KMFolder* KMailICalIfaceImpl::initScalixFolder( KMail::FolderContentsType contentsType )
02028 {
02029   // Figure out what type of folder this is supposed to be
02030   KMFolderType type = mFolderType;
02031   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02032 
02033   KMFolder* folder = 0;
02034 
02035   // Find all extra folders
02036   QStringList folderNames;
02037   QValueList<QGuardedPtr<KMFolder> > folderList;
02038   Q_ASSERT( kmkernel );
02039   Q_ASSERT( kmkernel->dimapFolderMgr() );
02040   kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
02041   QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
02042   for(; it != folderList.end(); ++it)
02043   {
02044     FolderStorage *storage = (*it)->storage();
02045 
02046     if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
02047       KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
02048 
02049       const QString attributes = imapFolder->folderAttributes();
02050       if ( attributes.contains( "X-SpecialFolder" ) ) {
02051         const Scalix::FolderAttributeParser parser( attributes );
02052         if ( contentsType == Scalix::Utils::scalixIdToContentsType( parser.folderClass() ) ) {
02053           folder = *it;
02054           break;
02055         }
02056       }
02057     }
02058   }
02059 
02060   if ( !folder ) {
02061     return 0;
02062   } else {
02063     FolderInfo info = readFolderInfo( folder );
02064     mFolderInfoMap.insert( folder, info );
02065     //kdDebug(5006) << "Found existing folder type " << itemType << " : " << folder->location()  << endl;
02066   }
02067 
02068   if( folder->canAccess() != 0 ) {
02069     KMessageBox::sorry(0, i18n("You do not have read/write permission to your folder.") );
02070     return 0;
02071   }
02072   folder->storage()->setContentsType( contentsType );
02073   folder->setSystemFolder( true );
02074   folder->storage()->writeConfig();
02075   folder->open( "scalixfolder" );
02076   connectFolder( folder );
02077   return folder;
02078 }
02079 
02080 void KMailICalIfaceImpl::connectFolder( KMFolder* folder )
02081 {
02082   // avoid multiple connections
02083   disconnect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
02084               this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
02085   disconnect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
02086               this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
02087   disconnect( folder, SIGNAL( expunged( KMFolder* ) ),
02088               this, SLOT( slotRefreshFolder( KMFolder* ) ) );
02089   disconnect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
02090               this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
02091   disconnect( folder, SIGNAL( nameChanged() ),
02092               this, SLOT( slotFolderRenamed() ) );
02093   disconnect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
02094               this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
02095 
02096   // Setup the signals to listen for changes
02097   connect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
02098            this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
02099   connect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
02100            this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
02101   connect( folder, SIGNAL( expunged( KMFolder* ) ),
02102            this, SLOT( slotRefreshFolder( KMFolder* ) ) );
02103   connect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
02104            this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
02105   connect( folder, SIGNAL( nameChanged() ),
02106            this, SLOT( slotFolderRenamed() ) );
02107   connect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
02108            this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
02109 
02110 }
02111 
02112 static void cleanupFolder( KMFolder* folder, KMailICalIfaceImpl* _this )
02113 {
02114   if( folder ) {
02115     folder->setSystemFolder( false );
02116     folder->disconnect( _this );
02117     folder->close("ifacefolder");
02118   }
02119 }
02120 
02121 void KMailICalIfaceImpl::cleanup()
02122 {
02123   cleanupFolder( mContacts, this );
02124   cleanupFolder( mCalendar, this );
02125   cleanupFolder( mNotes, this );
02126   cleanupFolder( mTasks, this );
02127   cleanupFolder( mJournals, this );
02128 
02129   mContacts = mCalendar = mNotes = mTasks = mJournals = 0;
02130 }
02131 
02132 QString KMailICalIfaceImpl::folderPixmap( KFolderTreeItem::Type type ) const
02133 {
02134   if( !mUseResourceIMAP )
02135     return QString::null;
02136 
02137   if( type == KFolderTreeItem::Contacts )
02138     return QString::fromLatin1( "kmgroupware_folder_contacts" );
02139   else if( type == KFolderTreeItem::Calendar )
02140     return QString::fromLatin1( "kmgroupware_folder_calendar" );
02141   else if( type == KFolderTreeItem::Notes )
02142     return QString::fromLatin1( "kmgroupware_folder_notes" );
02143   else if( type == KFolderTreeItem::Tasks )
02144     return QString::fromLatin1( "kmgroupware_folder_tasks" );
02145   else if( type == KFolderTreeItem::Journals )
02146     return QString::fromLatin1( "kmgroupware_folder_journals" );
02147 
02148   return QString::null;
02149 }
02150 
02151 static void reloadFolderTree()
02152 {
02153   // Make the folder tree show the icons or not
02154   kmkernel->folderMgr()->contentsChanged();
02155 }
02156 
02157 // This is a very light-weight and fast 'parser' to retrieve
02158 // a data entry from a vCal taking continuation lines
02159 // into account
02160 static void vPartMicroParser( const QString& str, QString& s )
02161 {
02162   QString line;
02163   uint len = str.length();
02164 
02165   for( uint i=0; i<len; ++i){
02166     if( str[i] == '\r' || str[i] == '\n' ){
02167       if( str[i] == '\r' )
02168         ++i;
02169       if( i+1 < len && str[i+1] == ' ' ){
02170         // found a continuation line, skip it's leading blanc
02171         ++i;
02172       }else{
02173         // found a logical line end, process the line
02174         if( line.startsWith( s ) ) {
02175           s = line.mid( s.length() + 1 );
02176           return;
02177         }
02178         line = "";
02179       }
02180     } else {
02181       line += str[i];
02182     }
02183   }
02184 
02185   // Not found. Clear it
02186   s.truncate(0);
02187 }
02188 
02189 // Returns the first child folder having the given annotation
02190 static QValueList<KMFolder*> findFolderByAnnotation( KMFolderDir* folderParentDir, const QString& annotation )
02191 {
02192   QValueList<KMFolder*> rv;
02193   QPtrListIterator<KMFolderNode> it( *folderParentDir );
02194   for ( ; it.current(); ++it ) {
02195     if ( !it.current()->isDir() ) {
02196       KMFolder* folder = static_cast<KMFolder *>( it.current() );
02197       if ( folder->folderType() == KMFolderTypeCachedImap ) {
02198         QString folderAnnotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
02199         //kdDebug(5006) << "findStandardResourceFolder: " << folder->name() << " has annotation " << folderAnnotation << endl;
02200         if ( folderAnnotation == annotation )
02201           rv.append( folder );
02202       }
02203     }
02204   }
02205   return rv;
02206 }
02207 
02208 KMailICalIfaceImpl::StandardFolderSearchResult KMailICalIfaceImpl::findStandardResourceFolder( KMFolderDir* folderParentDir, KMail::FolderContentsType contentsType )
02209 {
02210   if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
02211   {
02212     // Look for a folder with an annotation like "event.default"
02213     QValueList<KMFolder*> folders = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) + ".default" );
02214     if ( !folders.isEmpty() )
02215       return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundAndStandard );
02216 
02217     // Fallback: look for a folder with an annotation like "event"
02218     folders = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) );
02219     if ( !folders.isEmpty() )
02220       return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundByType );
02221 
02222     // Fallback: look for the folder by name (we'll need to change its type)
02223     KMFolderNode* node = folderParentDir->hasNamedFolder( localizedDefaultFolderName( contentsType ) );
02224     if ( node && !node->isDir() )
02225       return StandardFolderSearchResult( static_cast<KMFolder *>( node ), StandardFolderSearchResult::FoundByName );
02226 
02227     kdDebug(5006) << "findStandardResourceFolder: found no resource folder for " << s_folderContentsType[contentsType].annotation << endl;
02228     return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02229   }
02230   else // icalvcard: look up standard resource folders by name
02231   {
02232     KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
02233     unsigned int folderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
02234     if( folderLanguage > 3 ) folderLanguage = 0;
02235     KMFolderNode* node = folderParentDir->hasNamedFolder( folderName( itemType, folderLanguage ) );
02236     if ( !node || node->isDir() )
02237       return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02238     return StandardFolderSearchResult( static_cast<KMFolder*>( node ), StandardFolderSearchResult::FoundAndStandard );
02239   }
02240 }
02241 
02242 /* We treat all folders as relevant wrt alarms for which we have Administer
02243  * rights or for which the "Incidences relevant for everyone" annotation has
02244  * been set. It can be reasonably assumed that those are "ours". All local folders
02245  * must be ours anyhow. */
02246 bool KMailICalIfaceImpl::folderIsAlarmRelevant( const KMFolder *folder )
02247 {
02248   bool administerRights = true;
02249   bool relevantForOwner = true;
02250   bool relevantForEveryone = false;
02251   if ( folder->folderType() == KMFolderTypeImap ) {
02252     const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
02253     administerRights =
02254       imapFolder->userRights() <= 0 || imapFolder->userRights() & KMail::ACLJobs::Administer;
02255   }
02256   if ( folder->folderType() == KMFolderTypeCachedImap ) {
02257     const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
02258     administerRights =
02259       dimapFolder->userRights() <= 0 || dimapFolder->userRights() & KMail::ACLJobs::Administer;
02260     relevantForOwner = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor () == KMFolderCachedImap::IncForAdmins );
02261     relevantForEveryone = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor() == KMFolderCachedImap::IncForReaders );
02262   }
02263 #if 0
02264   kdDebug(5006) << k_funcinfo << endl;
02265   kdDebug(5006) << "Folder: " << folder->label() << " has administer rights: " << administerRights << endl;
02266   kdDebug(5006) << "and is relevant for owner: " << relevantForOwner <<  endl;
02267   kdDebug(5006) << "and relevant for everyone: "  << relevantForEveryone << endl;
02268 #endif
02269   return ( administerRights && relevantForOwner ) || relevantForEveryone;
02270 }
02271 
02272 void KMailICalIfaceImpl::setResourceQuiet(bool q)
02273 {
02274   mResourceQuiet = q;
02275 }
02276 
02277 bool KMailICalIfaceImpl::isResourceQuiet() const
02278 {
02279   return mResourceQuiet;
02280 }
02281 
02282 
02283 bool KMailICalIfaceImpl::addSubresource( const QString& resource,
02284                                          const QString& parent,
02285                                          const QString& contentsType )
02286 {
02287   kdDebug(5006) << "Adding subresource to parent: " << parent << " with name: " << resource << endl;
02288   kdDebug(5006) << "contents type: " << contentsType << endl;
02289   KMFolder *folder = findResourceFolder( parent );
02290   KMFolderDir *parentFolderDir = !parent.isEmpty() && folder ? folder->createChildFolder(): mFolderParentDir;
02291   if ( !parentFolderDir || parentFolderDir->hasNamedFolder( resource ) ) return false;
02292 
02293   QString msg;
02294   if ( parentFolderDir->owner() && !parentFolderDir->owner()->isValidName( resource, msg ) ) {
02295     KMessageBox::error( 0, msg );
02296     return false;
02297   }
02298 
02299   KMFolderType type = mFolderType;
02300   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02301 
02302   KMFolder* newFolder = parentFolderDir->createFolder( resource, false, type );
02303   if ( !newFolder ) return false;
02304   if( mFolderType == KMFolderTypeImap )
02305     static_cast<KMFolderImap*>( folder->storage() )->createFolder( resource );
02306 
02307   StorageFormat defaultFormat = GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
02308   setStorageFormat( newFolder, folder ? storageFormat( folder ) : defaultFormat );
02309   newFolder->storage()->setContentsType( folderContentsType( contentsType ) );
02310   newFolder->storage()->writeConfig();
02311   newFolder->open( "ical_subresource" );
02312   connectFolder( newFolder );
02313   reloadFolderTree();
02314 
02315   return true;
02316 }
02317 
02318 bool KMailICalIfaceImpl::removeSubresource( const QString& location )
02319 {
02320   kdDebug(5006) << k_funcinfo << endl;
02321 
02322   KMFolder *folder = findResourceFolder( location );
02323 
02324   // We don't allow the default folders to be deleted, so check for
02325   // those first. It would be nicer to produce a more meaningful error,
02326   // or prevent deletion of the builtin folders from the gui already.
02327   if ( !folder || isStandardResourceFolder( folder ) )
02328       return false;
02329 
02330   // the folder will be removed, which implies closed, so make sure
02331   // nothing is using it anymore first
02332   subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), location );
02333   mExtraFolders.remove( location );
02334   folder->disconnect( this );
02335 
02336   if ( folder->folderType() == KMFolderTypeImap )
02337     kmkernel->imapFolderMgr()->remove( folder );
02338   else if ( folder->folderType() == KMFolderTypeCachedImap ) {
02339     // Deleted by user -> tell the account (see KMFolderCachedImap::listDirectory2)
02340     KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( folder->storage() );
02341     KMAcctCachedImap* acct = storage->account();
02342     if ( acct )
02343       acct->addDeletedFolder( folder );
02344     kmkernel->dimapFolderMgr()->remove( folder );
02345   }
02346   return true;
02347 }
02348 
02349 void KMailICalIfaceImpl::syncFolder(KMFolder * folder) const
02350 {
02351   if ( kmkernel->isOffline() || !GlobalSettings::immediatlySyncDIMAPOnGroupwareChanges() )
02352     return;
02353   KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
02354   if ( !dimapFolder )
02355     return;
02356   // check if the folder exists already, otherwise sync its parent as well to create it
02357   if ( dimapFolder->imapPath().isEmpty() ) {
02358     if ( folder->parent() && folder->parent()->owner() )
02359       syncFolder( folder->parent()->owner() );
02360     else
02361       return;
02362   }
02363   dimapFolder->account()->processNewMailInFolder( folder );
02364 }
02365 
02366 #include "kmailicalifaceimpl.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys