kmail

kmailicalifaceimpl.cpp

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