kmail

kmailicalifaceimpl.cpp

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