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