kmail

kmailicalifaceimpl.cpp

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