kmail

kmailicalifaceimpl.cpp

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