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