kmail

kmailicalifaceimpl.cpp

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