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 TQt library by Trolltech AS, Norway (or with modified versions
00026     of TQt that use the same license as TQt), 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     TQt.  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 <tqfile.h>
00065 #include <tqmap.h>
00066 #include <tqtextcodec.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 TQMap<TQString, TQString> *KMailICalIfaceImpl::mSubResourceUINamesMap = new TQMap<TQString, TQString>;
00080 
00081 // Local helper methods
00082 static void vPartMicroParser( const TQString& str, TQString& 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 TQString folderContentsType( KMail::FolderContentsType type )
00102 {
00103   return s_folderContentsType[type].contentsTypeStr;
00104 }
00105 
00106 static TQString 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 TQString& 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 TQString 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" ), TQObject( 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, TQT_SIGNAL( configChanged() ), this, TQT_SLOT( readConfig() ) );
00165   connect( kmkernel, TQT_SIGNAL( folderRemoved( KMFolder* ) ),
00166            this, TQT_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              && TQString( 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 TQString& 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 TQString& attachmentURL,
00243                                            const TQString& attachmentName,
00244                                            const TQString& 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 TQString fileName( url.path() );
00254     TQFile file( fileName );
00255     if( file.open( IO_ReadOnly ) ) {
00256       TQByteArray 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 TQCString sType    = attachmentMimetype.left( iSlash   ).latin1();
00265       const TQCString sSubtype = attachmentMimetype.mid(  iSlash+1 ).latin1();
00266       msgPart.setTypeStr( sType );
00267       msgPart.setSubtypeStr( sSubtype );
00268       TQCString ctd("attachment;\n  filename=\"");
00269       ctd.append( attachmentName.latin1() );
00270       ctd.append("\"");
00271       msgPart.setContentDisposition( ctd );
00272       TQValueList<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 TQString& mimetype, TQString& s )
00311 {
00312   const int iSlash = mimetype.find('/');
00313   const TQCString sType    = mimetype.left( iSlash   ).latin1();
00314   const TQCString 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( TQTextCodec::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 TQString& 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 TQString 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 TQ_UINT32 KMailICalIfaceImpl::addIncidenceKolab( KMFolder& folder,
00406                                                 const TQString& subject,
00407                                                 const TQString& plainTextBody,
00408                                                 const TQMap<TQCString, TQString>& customHeaders,
00409                                                 const TQStringList& attachmentURLs,
00410                                                 const TQStringList& attachmentNames,
00411                                                 const TQStringList& attachmentMimetypes )
00412 {
00413   kdDebug(5006) << "KMailICalIfaceImpl::addIncidenceKolab( " << attachmentNames << " )" << endl;
00414 
00415   TQ_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   TQMap<TQCString, TQString>::ConstIterator ith = customHeaders.begin();
00425   const TQMap<TQCString, TQString>::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   TQStringList::ConstIterator itmime = attachmentMimetypes.begin();
00445   TQStringList::ConstIterator iturl = attachmentURLs.begin();
00446   for( TQStringList::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 TQString& resource,
00480                                                TQ_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 TQString& mimetype,
00512                                               const TQString& 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 TQMap<TQ_UINT32, TQString> KMailICalIfaceImpl::incidencesKolab( const TQString& mimetype,
00534                                                              const TQString& resource,
00535                                                              int startIndex,
00536                                                              int nbMessages )
00537 {
00541 
00542   TQMap<TQ_UINT32, TQString> 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   kdDebug(5006) << k_funcinfo << "Getting incidences (" << mimetype << ") for folder " << f->label()
00555                 << ", starting with index " << startIndex << ", " << nbMessages << " messages." << endl;
00556   kdDebug(5006) << "The folder has " << f->count() << " messages." << endl;
00557 
00558   int stopIndex = nbMessages == -1 ? f->count() :
00559                   TQMIN( f->count(), startIndex + nbMessages );
00560 
00561   for(int i = startIndex; i < stopIndex; ++i) {
00562 #if 0
00563     bool unget = !f->isMessage(i);
00564     KMMessage* msg = f->getMsg( i );
00565 #else // faster
00566     KMMessage* msg = f->storage()->readTemporaryMsg(i);
00567 #endif
00568     if ( msg ) {
00569       const int iSlash = mimetype.find('/');
00570       const TQCString sType    = mimetype.left( iSlash   ).latin1();
00571       const TQCString sSubtype = mimetype.mid(  iSlash+1 ).latin1();
00572       if ( sType.isEmpty() || sSubtype.isEmpty() ) {
00573         kdError(5006) << mimetype << " not an type/subtype combination" << endl;
00574       } else {
00575         DwBodyPart* dwPart = findBodyPartByMimeType( *msg, sType, sSubtype );
00576         if ( dwPart ) {
00577           KMMessagePart msgPart;
00578           KMMessage::bodyPart(dwPart, &msgPart);
00579           aMap.insert(msg->getMsgSerNum(), msgPart.bodyToUnicode( TQTextCodec::codecForName( "utf8" ) ));
00580         } else {
00581           // Check if the whole message has the right types. This is what
00582           // happens in the case of ical storage, where the whole mail is
00583           // the data
00584           const TQCString type( msg->typeStr() );
00585           const TQCString subtype( msg->subtypeStr() );
00586           if (type.lower() == sType && subtype.lower() == sSubtype ) {
00587             aMap.insert( msg->getMsgSerNum(), msg->bodyToUnicode() );
00588           }
00589           // This is *not* an error: it may be that not all of the messages
00590           // have a message part that is matching the wanted MIME type
00591         }
00592       }
00593 #if 0
00594       if( unget ) f->unGetMsg(i);
00595 #else
00596       delete msg;
00597 #endif
00598     } else {
00599       kdDebug(5006) << k_funcinfo << " Unable to retrieve message " << i << " for incidence!" << endl;
00600     }
00601   }
00602   f->close( "incidences" );
00603   return aMap;
00604 }
00605 
00606 
00607 /* Called when a message that was downloaded from an online imap folder
00608  * arrives. Needed when listing incidences on online account folders. */
00609 // TODO: Till, port me
00610 void KMailICalIfaceImpl::slotMessageRetrieved( KMMessage* msg )
00611 {
00612   if( !msg ) return;
00613 
00614   KMFolder *parent = msg->parent();
00615   Q_ASSERT( parent );
00616   TQ_UINT32 sernum = msg->getMsgSerNum();
00617 
00618   // do we have an accumulator for this folder?
00619   Accumulator *ac = mAccumulators.find( parent->location() );
00620   if( ac ) {
00621     TQString s;
00622     if ( !vPartFoundAndDecoded( msg, s ) ) return;
00623     TQString uid( "UID" );
00624     vPartMicroParser( s, uid );
00625     const TQ_UINT32 sernum = msg->getMsgSerNum();
00626     mUIDToSerNum.insert( uid, sernum );
00627     ac->add( s );
00628     if( ac->isFull() ) {
00629       /* if this was the last one we were waiting for, tell the resource
00630        * about the new incidences and clean up. */
00631       //asyncLoadResult( ac->incidences, ac->type, ac->folder );
00632       mAccumulators.remove( ac->folder ); // autodelete
00633     }
00634   } else {
00635     /* We are not accumulating for this folder, so this one was added
00636      * by KMail. Do your thang. */
00637      slotIncidenceAdded( msg->parent(), msg->getMsgSerNum() );
00638   }
00639 
00640   if ( mTheUnGetMes.contains( sernum ) ) {
00641     mTheUnGetMes.remove( sernum );
00642     int i = 0;
00643     KMFolder* folder = 0;
00644     KMMsgDict::instance()->getLocation( sernum, &folder, &i );
00645     folder->unGetMsg( i );
00646   }
00647 }
00648 
00649 static int dimapAccountCount()
00650 {
00651   KMail::AccountManager *mgr = kmkernel->acctMgr();
00652   KMAccount *account = mgr->first();
00653   int count = 0;
00654   while ( account ) {
00655     if ( dynamic_cast<KMAcctCachedImap*>( account ) )
00656       ++count;
00657     account = mgr->next();
00658   }
00659   return count;
00660 }
00661 
00662 int KMailICalIfaceImpl::dimapAccounts()
00663 {
00664   return dimapAccountCount();
00665 }
00666 
00667 static TQString subresourceLabelForPresentation( const KMFolder * folder )
00668 {
00669     if( KMailICalIfaceImpl::getResourceMap()->contains( folder->location() ) ) {
00670         return folder->label();
00671     }
00672 
00673     TQString label = folder->prettyURL();
00674     TQStringList parts = TQStringList::split( TQString::fromLatin1("/"), label );
00675 
00676     // In the common special case of some other user's folder shared with us
00677     // the url looks like "Server Name/user/$USERNAME/Folder/Name". Make
00678     // those a bit nicer.
00679     if ( parts[1] == TQString::fromLatin1("user") ) {
00680         TQStringList remainder(parts);
00681         remainder.pop_front();
00682         remainder.pop_front();
00683         remainder.pop_front();
00684         label = i18n("%1's %2")
00685             .arg( parts[2] )
00686             .arg( remainder.join( TQString::fromLatin1("/") ) );
00687     }
00688     // Another special case is our own folders, under the imap INBOX, make
00689     // those prettier too
00690     const KMFolder *parent = folder;
00691     while ( parent->parent() && parent->parent()->owner() ) {
00692       parent = parent->parent()->owner();
00693       if ( parent->isSystemFolder() ) {
00694         TQStringList remainder(parts);
00695         remainder.pop_front();
00696         remainder.pop_front();
00697         if ( dimapAccountCount() > 1 ) {
00698           // Fix kolab issue 2531 folder->storage() )->account() can be null
00699           if( folder->storage() && static_cast<const KMFolderCachedImap*>( folder->storage() )->account() ) {
00700           label = i18n( "My %1 (%2)")
00701               .arg( remainder.join( TQString::fromLatin1("/") ),
00702                     static_cast<const KMFolderCachedImap*>( folder->storage() )->account()->name() );
00703           } else {
00704             label = i18n("My %1")
00705               .arg( remainder.join( TQString::fromLatin1("/") ) );
00706           }
00707         } else {
00708           label = i18n("My %1")
00709               .arg( remainder.join( TQString::fromLatin1("/") ) );
00710         }
00711         break;
00712       }
00713     }
00714     return label;
00715 }
00716 
00717 /* list all available subresources */
00718 TQValueList<KMailICalIfaceImpl::SubResource> KMailICalIfaceImpl::subresourcesKolab( const TQString& contentsType )
00719 {
00720   TQValueList<SubResource> subResources;
00721 
00722   // Add the default one
00723   KMFolder* f = folderFromType( contentsType, TQString() );
00724   if ( f ) {
00725     subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
00726                                       f->isWritable(), folderIsAlarmRelevant( f ) ) );
00727     kdDebug(5006) << "Adding(1) folder " << f->location() << "    " <<
00728       ( !f->isWritable() ? "readonly" : "" ) << endl;
00729   }
00730 
00731   // get the extra ones
00732   const KMail::FolderContentsType t = folderContentsType( contentsType );
00733   TQDictIterator<ExtraFolder> it( mExtraFolders );
00734   for ( ; it.current(); ++it ){
00735     f = it.current()->folder;
00736     if ( f && f->storage()->contentsType() == t ) {
00737       subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
00738                                         f->isWritable(), folderIsAlarmRelevant( f ) ) );
00739       kdDebug(5006) << "Adding(2) folder " << f->location() << "     " <<
00740               ( !f->isWritable() ? "readonly" : "" ) << endl;
00741     }
00742   }
00743 
00744   if ( subResources.isEmpty() )
00745     kdDebug(5006) << "subresourcesKolab: No folder found for " << contentsType << endl;
00746   return subResources;
00747 }
00748 
00749 bool KMailICalIfaceImpl::triggerSync( const TQString& contentsType )
00750 {
00751   kdDebug(5006) << k_funcinfo << endl;
00752   TQValueList<KMailICalIfaceImpl::SubResource> folderList = subresourcesKolab( contentsType );
00753   for ( TQValueList<KMailICalIfaceImpl::SubResource>::const_iterator it( folderList.begin() ),
00754                                                                     end( folderList.end() );
00755         it != end ; ++it ) {
00756     KMFolder * const f = findResourceFolder( (*it).location );
00757     if ( !f ) continue;
00758     if ( f->folderType() == KMFolderTypeImap || f->folderType() == KMFolderTypeCachedImap ) {
00759       if ( !kmkernel->askToGoOnline() ) {
00760         return false;
00761       }
00762     }
00763 
00764     if ( f->folderType() == KMFolderTypeImap ) {
00765       KMFolderImap *imap = static_cast<KMFolderImap*>( f->storage() );
00766       imap->getAndCheckFolder();
00767     } else if ( f->folderType() == KMFolderTypeCachedImap ) {
00768       KMFolderCachedImap* cached = static_cast<KMFolderCachedImap*>( f->storage() );
00769       if ( cached->account() ) {
00770         cached->account()->processNewMailInFolder( f );
00771       }
00772     }
00773   }
00774   return true;
00775 }
00776 
00777 /* Used by the resource to query whether folders are writable. */
00778 bool KMailICalIfaceImpl::isWritableFolder( const TQString& type,
00779                                            const TQString& resource )
00780 {
00781   KMFolder* f = folderFromType( type, resource );
00782   if ( !f )
00783     // Definitely not writable
00784     return false;
00785 
00786   return f->isWritable();
00787 }
00788 
00789 /* Used by the resource to query the storage format of the folder. */
00790 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( const TQString& resource )
00791 {
00792   StorageFormat format;
00793   KMFolder* f = findResourceFolder( resource );
00794   if ( f )
00795     format = storageFormat( f );
00796   else
00797     format = globalStorageFormat();
00798   return format;
00799 }
00800 
00815 TQ_UINT32 KMailICalIfaceImpl::update( const TQString& resource,
00816                                      TQ_UINT32 sernum,
00817                                      const TQString& subject,
00818                                      const TQString& plainTextBody,
00819                                      const TQMap<TQCString, TQString>& customHeaders,
00820                                      const TQStringList& attachmentURLs,
00821                                      const TQStringList& attachmentMimetypes,
00822                                      const TQStringList& attachmentNames,
00823                                      const TQStringList& deletedAttachments )
00824 {
00825   TQ_UINT32 rc = 0;
00826 
00827    if( !mUseResourceIMAP )
00828     return rc;
00829 
00830   Q_ASSERT( !resource.isEmpty() );
00831 
00832   kdDebug(5006) << "KMailICalIfaceImpl::update( " << resource << ", " << sernum << " )\n";
00833   kdDebug(5006) << attachmentURLs << "\n";
00834   kdDebug(5006) << attachmentMimetypes << "\n";
00835   kdDebug(5006) << attachmentNames << "\n";
00836   kdDebug(5006) << "deleted attachments:" << deletedAttachments << "\n";
00837 
00838   // Find the folder
00839   KMFolder* f = findResourceFolder( resource );
00840   if( !f ) {
00841     kdError(5006) << "update(" << resource << ") : Not an IMAP resource folder" << endl;
00842     return rc;
00843   }
00844 
00845   f->open( "ifaceupdate" );
00846 
00847   KMMessage* msg = 0;
00848   if ( sernum != 0 ) {
00849     msg = findMessageBySerNum( sernum, f );
00850     if ( !msg ) return 0;
00851     // Message found - make a copy and update it:
00852     KMMessage* newMsg = new KMMessage( *msg );
00853     newMsg->setSubject( subject );
00854     TQMap<TQCString, TQString>::ConstIterator ith = customHeaders.begin();
00855     const TQMap<TQCString, TQString>::ConstIterator ithEnd = customHeaders.begin();
00856     for ( ; ith != ithEnd ; ++ith )
00857       newMsg->setHeaderField( ith.key(), ith.data() );
00858     newMsg->setParent( 0 ); // workaround strange line in KMMsgBase::assign. newMsg is not in any folder yet.
00859     // Note that plainTextBody isn't used in this branch. We assume it's still valid from when the mail was created.
00860 
00861     // Delete some attachments according to list
00862     for( TQStringList::ConstIterator it = deletedAttachments.begin();
00863          it != deletedAttachments.end();
00864          ++it ){
00865       if( !deleteAttachment( *newMsg, *it ) ){
00866         // Note: It is _not_ an error if an attachment was already deleted.
00867       }
00868     }
00869 
00870     const KMail::FolderContentsType t = f->storage()->contentsType();
00871     const TQCString type = msg->typeStr();
00872     const TQCString subtype = msg->subtypeStr();
00873     const bool messageWasIcalVcardFormat = ( type.lower() == "text" &&
00874         ( subtype.lower() == "calendar" || subtype.lower() == "x-vcard" ) );
00875 
00876     if ( storageFormat( f ) == StorageIcalVcard ) {
00877       //kdDebug(5006) << k_funcinfo << " StorageFormatIcalVcard " << endl;
00878       if ( !messageWasIcalVcardFormat ) {
00879         setIcalVcardContentTypeHeader( newMsg, t, f );
00880       }
00881       newMsg->setBodyEncoded( plainTextBody.utf8() );
00882     } else if ( storageFormat( f ) == StorageXML ) {
00883       if ( messageWasIcalVcardFormat ) {
00884         // this was originally an ical event, but the folder changed to xml,
00885         // convert
00886        setXMLContentTypeHeader( newMsg, plainTextBody );
00887       }
00888       //kdDebug(5006) << k_funcinfo << " StorageFormatXML " << endl;
00889       // Add all attachments by reading them from their temp. files
00890       TQStringList::ConstIterator iturl = attachmentURLs.begin();
00891       TQStringList::ConstIterator itmime = attachmentMimetypes.begin();
00892       TQStringList::ConstIterator itname = attachmentNames.begin();
00893       for( ;
00894           iturl != attachmentURLs.end()
00895           && itmime != attachmentMimetypes.end()
00896           && itname != attachmentNames.end();
00897           ++iturl, ++itname, ++itmime ){
00898         bool byname = !(*itmime).startsWith( "application/x-vnd.kolab." );
00899         if( !updateAttachment( *newMsg, *iturl, *itname, *itmime, byname ) ){
00900           kdDebug(5006) << "Attachment error, can not update attachment " << *iturl << endl;
00901           break;
00902         }
00903       }
00904     }
00905 
00906     //debugBodyParts( "in update, before cleanup", *newMsg );
00907 
00908     // This is necessary for the headers to be readable later on
00909     newMsg->cleanupHeader();
00910 
00911     //debugBodyParts( "in update, after cleanup", *newMsg );
00912 
00913     deleteMsg( msg );
00914     if ( f->addMsg( newMsg ) == 0 ) {
00915       // Message stored
00916       rc = newMsg->getMsgSerNum();
00917       kdDebug(5006) << "forget about " << sernum << ", it's " << rc << " now" << endl;
00918     }
00919     addFolderChange( f, Contents );
00920     syncFolder( f );
00921   } else {
00922     // Message not found - store it newly
00923     rc = addIncidenceKolab( *f, subject, plainTextBody, customHeaders,
00924                             attachmentURLs,
00925                             attachmentNames,
00926                             attachmentMimetypes );
00927   }
00928 
00929   f->close("ifaceupdate");
00930   return rc;
00931 }
00932 
00933 KURL KMailICalIfaceImpl::getAttachment( const TQString& resource,
00934                                         TQ_UINT32 sernum,
00935                                         const TQString& filename )
00936 {
00937   // This finds the attachment with the filename, saves it to a
00938   // temp file and returns a URL to it. It's up to the resource
00939   // to delete the tmp file later.
00940   if( !mUseResourceIMAP )
00941     return KURL();
00942 
00943   kdDebug(5006) << "KMailICalIfaceImpl::getAttachment( "
00944                 << resource << ", " << sernum << ", " << filename << " )\n";
00945 
00946   // Find the folder
00947   KMFolder* f = findResourceFolder( resource );
00948   if( !f ) {
00949     kdError(5006) << "getAttachment(" << resource << ") : Not an IMAP resource folder" << endl;
00950     return KURL();
00951   }
00952   if ( storageFormat( f ) != StorageXML ) {
00953     kdError(5006) << "getAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
00954     return KURL();
00955   }
00956 
00957   KURL url;
00958 
00959   bool bOK = false;
00960   bool quiet = mResourceQuiet;
00961   mResourceQuiet = true;
00962 
00963   KMMessage* msg = findMessageBySerNum( sernum, f );
00964   if( msg ) {
00965     // Message found - look for the attachment:
00966 
00967     DwBodyPart* part = findBodyPart( *msg, filename );
00968     if ( part ) {
00969       // Save the contents of the attachment.
00970       KMMessagePart aPart;
00971       msg->bodyPart( part, &aPart );
00972       TQByteArray rawData( aPart.bodyDecodedBinary() );
00973 
00974       KTempFile file;
00975       file.file()->writeBlock( rawData.data(), rawData.size() );
00976 
00977       url.setPath( file.name() );
00978 
00979       bOK = true;
00980     }
00981 
00982     if( !bOK ){
00983       kdDebug(5006) << "Attachment " << filename << " not found." << endl;
00984     }
00985   }else{
00986     kdDebug(5006) << "Message not found." << endl;
00987   }
00988 
00989   mResourceQuiet = quiet;
00990   return url;
00991 }
00992 
00993 TQString KMailICalIfaceImpl::attachmentMimetype( const TQString & resource,
00994                                                 TQ_UINT32 sernum,
00995                                                 const TQString & filename )
00996 {
00997   if( !mUseResourceIMAP )
00998     return TQString();
00999   KMFolder* f = findResourceFolder( resource );
01000   if( !f || storageFormat( f ) != StorageXML ) {
01001     kdError(5006) << "attachmentMimetype(" << resource << ") : Wrong folder" << endl;
01002     return TQString();
01003   }
01004 
01005   KMMessage* msg = findMessageBySerNum( sernum, f );
01006   if( msg ) {
01007     // Message found - look for the attachment:
01008     DwBodyPart* part = findBodyPart( *msg, filename );
01009     if ( part ) {
01010       KMMessagePart kmPart;
01011       msg->bodyPart( part, &kmPart );
01012       return TQString( kmPart.typeStr() ) + "/" + TQString( kmPart.subtypeStr() );
01013     } else {
01014       kdDebug(5006) << "Attachment " << filename << " not found." << endl;
01015     }
01016   } else {
01017     kdDebug(5006) << "Message not found." << endl;
01018   }
01019 
01020   return TQString();
01021 }
01022 
01023 TQStringList KMailICalIfaceImpl::listAttachments(const TQString & resource, TQ_UINT32 sernum)
01024 {
01025   TQStringList rv;
01026   if( !mUseResourceIMAP )
01027     return rv;
01028 
01029   // Find the folder
01030   KMFolder* f = findResourceFolder( resource );
01031   if( !f ) {
01032     kdError(5006) << "listAttachments(" << resource << ") : Not an IMAP resource folder" << endl;
01033     return rv;
01034   }
01035   if ( storageFormat( f ) != StorageXML ) {
01036     kdError(5006) << "listAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
01037     return rv;
01038   }
01039 
01040   KMMessage* msg = findMessageBySerNum( sernum, f );
01041   if( msg ) {
01042     for ( DwBodyPart* part = msg->getFirstDwBodyPart(); part; part = part->Next() ) {
01043       if ( part->hasHeaders() ) {
01044         TQString name;
01045         DwMediaType& contentType = part->Headers().ContentType();
01046         if ( TQString( contentType.SubtypeStr().c_str() ).startsWith( "x-vnd.kolab." )
01047            || TQString( contentType.SubtypeStr().c_str() ).contains( "tnef" ) )
01048           continue;
01049         if ( !part->Headers().ContentDisposition().Filename().empty() )
01050           name = part->Headers().ContentDisposition().Filename().c_str();
01051         else if ( !contentType.Name().empty() )
01052           name = contentType.Name().c_str();
01053         if ( !name.isEmpty() )
01054           rv.append( name );
01055       }
01056     }
01057   } else {
01058     kdDebug(5006) << "Message not found." << endl;
01059   }
01060 
01061   return rv;
01062 }
01063 
01064 
01065 // ============================================================================
01066 
01067 /* KMail part of the interface. These slots are connected to the resource
01068  * folders and inform us of folders or incidences in them changing, being
01069  * added or going away. */
01070 
01071 void KMailICalIfaceImpl::slotFolderRemoved( KMFolder* folder )
01072 {
01073   // pretend the folder just changed back to the mail type, which
01074   // does the right thing, namely remove resource
01075   folderContentsTypeChanged( folder, KMail::ContentsTypeMail );
01076   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01077   configGroup.deleteEntry( folder->idString() + "-storageFormat" );
01078   configGroup.deleteEntry( folder->idString() + "-changes" );
01079 }
01080 
01081 // KMail added a file to one of the groupware folders
01082 void KMailICalIfaceImpl::slotIncidenceAdded( KMFolder* folder,
01083                                              TQ_UINT32 sernum )
01084 {
01085   if( mResourceQuiet || !mUseResourceIMAP )
01086     return;
01087 
01088 //  kdDebug(5006) << "KMailICalIfaceImpl::slotIncidenceAdded" << endl;
01089   TQString type = folderContentsType( folder->storage()->contentsType() );
01090   if( type.isEmpty() ) {
01091     kdError(5006) << "Not an IMAP resource folder" << endl;
01092     return;
01093   }
01094   // Get the index of the mail
01095   int i = 0;
01096   KMFolder* aFolder = 0;
01097   KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
01098   assert( folder == aFolder );
01099 
01100   bool unget = !folder->isMessage( i );
01101   TQString s;
01102   TQString uid( "UID" );
01103   KMMessage *msg = folder->getMsg( i );
01104   if( !msg ) return;
01105   if( msg->isComplete() ) {
01106 
01107     bool ok = false;
01108     StorageFormat format = storageFormat( folder );
01109     switch( format ) {
01110       case StorageIcalVcard:
01111         // Read the iCal or vCard
01112         ok = vPartFoundAndDecoded( msg, s );
01113         if ( ok )
01114           vPartMicroParser( s, uid );
01115         break;
01116       case StorageXML:
01117         // Read the XML from the attachment with the given mimetype
01118         if ( kolabXMLFoundAndDecoded( *msg,
01119               folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
01120           uid = msg->subject();
01121           ok = true;
01122         }
01123         break;
01124     }
01125     if ( !ok ) {
01126       if ( unget )
01127         folder->unGetMsg( i );
01128       return;
01129     }
01130     const TQ_UINT32 sernum = msg->getMsgSerNum();
01131     mUIDToSerNum.insert( uid, sernum );
01132 
01133     // tell the resource if we didn't trigger this ourselves
01134     if ( mInTransit.contains( uid ) ) {
01135       mInTransit.remove( uid );
01136     }
01137     incidenceAdded( type, folder->location(), sernum, format, s );
01138   } else {
01139     // go get the rest of it, then try again
01140     // TODO: Till, port me
01141     if ( unget ) mTheUnGetMes.insert( msg->getMsgSerNum(), true );
01142     FolderJob *job = msg->parent()->createJob( msg );
01143     connect( job, TQT_SIGNAL( messageRetrieved( KMMessage* ) ),
01144         this, TQT_SLOT( slotMessageRetrieved( KMMessage* ) ) );
01145     job->start();
01146     return;
01147   }
01148   if( unget ) folder->unGetMsg(i);
01149 }
01150 
01151 // KMail deleted a file
01152 void KMailICalIfaceImpl::slotIncidenceDeleted( KMFolder* folder,
01153                                                TQ_UINT32 sernum )
01154 {
01155   if( mResourceQuiet || !mUseResourceIMAP )
01156     return;
01157 
01158   TQString type = folderContentsType( folder->storage()->contentsType() );
01159   //kdDebug(5006) << folder << " " << type << " " << sernum << endl;
01160   if( !type.isEmpty() ) {
01161     // Get the index of the mail
01162     int i = 0;
01163     KMFolder* aFolder = 0;
01164     KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
01165     assert( folder == aFolder );
01166 
01167     // Read the iCal or vCard
01168     bool unget = !folder->isMessage( i );
01169     TQString s;
01170     bool ok = false;
01171     KMMessage* msg = folder->getMsg( i );
01172     TQString uid( "UID" );
01173     switch( storageFormat( folder ) ) {
01174     case StorageIcalVcard:
01175         if( vPartFoundAndDecoded( msg, s ) ) {
01176             vPartMicroParser( s, uid );
01177             ok = true;
01178         }
01179         break;
01180     case StorageXML:
01181         if ( kolabXMLFoundAndDecoded( *msg, folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
01182           uid = msg->subject();
01183           ok = true;
01184         }
01185         break;
01186     }
01187     if ( ok ) {
01188         kdDebug(5006) << "Emitting DCOP signal incidenceDeleted( "
01189                       << type << ", " << folder->location() << ", " << uid
01190                       << " )" << endl;
01191         incidenceDeleted( type, folder->location(), uid );
01192     }
01193     if( unget ) folder->unGetMsg(i);
01194   } else
01195     kdError(5006) << "Not a groupware folder" << endl;
01196 }
01197 
01198 // KMail orders a refresh
01199 void KMailICalIfaceImpl::slotRefresh( const TQString& type )
01200 {
01201   if( mUseResourceIMAP ) {
01202     signalRefresh( type, TQString() /* PENDING(bo) folder->location() */ );
01203     kdDebug(5006) << "Emitting DCOP signal signalRefresh( " << type << " )" << endl;
01204   }
01205 }
01206 
01207 // This is among other things called when an expunge of a folder happens
01208 void KMailICalIfaceImpl::slotRefreshFolder( KMFolder* folder)
01209 {
01210   // TODO: The resources would of course be better off, if only this
01211   // folder would need refreshing. Currently it just orders a reload of
01212   // the type of the folder
01213   if( mUseResourceIMAP && folder ) {
01214     if( folder == mCalendar || folder == mContacts
01215         || folder == mNotes || folder == mTasks
01216         || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01217       // Refresh the folder of this type
01218       KMail::FolderContentsType ct = folder->storage()->contentsType();
01219       slotRefresh( s_folderContentsType[ct].contentsTypeStr );
01220     }
01221   }
01222 }
01223 
01224 /****************************
01225  * The folder and message stuff code
01226  */
01227 
01228 KMFolder* KMailICalIfaceImpl::folderFromType( const TQString& type,
01229                                               const TQString& folder )
01230 {
01231   if( mUseResourceIMAP ) {
01232     KMFolder* f = 0;
01233     if ( !folder.isEmpty() ) {
01234       f = extraFolder( type, folder );
01235       if ( f )
01236         return f;
01237     }
01238 
01239     if( type == "Calendar" ) f = mCalendar;
01240     else if( type == "Contact" ) f = mContacts;
01241     else if( type == "Note" ) f = mNotes;
01242     else if( type == "Task" || type == "Todo" ) f = mTasks;
01243     else if( type == "Journal" ) f = mJournals;
01244 
01245     if ( f && ( folder.isEmpty() || folder == f->location() ) )
01246       return f;
01247 
01248     kdError(5006) << "No folder ( " << type << ", " << folder << " )\n";
01249   }
01250 
01251   return 0;
01252 }
01253 
01254 
01255 // Returns true if folder is a resource folder. If the resource isn't enabled
01256 // this always returns false
01257 bool KMailICalIfaceImpl::isResourceFolder( KMFolder* folder ) const
01258 {
01259   return mUseResourceIMAP && folder &&
01260     ( isStandardResourceFolder( folder ) || mExtraFolders.find( folder->location() )!=0 );
01261 }
01262 
01263 bool KMailICalIfaceImpl::isStandardResourceFolder( KMFolder* folder ) const
01264 {
01265   return ( folder == mCalendar || folder == mTasks || folder == mJournals ||
01266            folder == mNotes || folder == mContacts );
01267 }
01268 
01269 bool KMailICalIfaceImpl::hideResourceFolder( KMFolder* folder ) const
01270 {
01271   return mHideFolders && isResourceFolder( folder );
01272 }
01273 
01274 bool KMailICalIfaceImpl::hideResourceAccountRoot( KMFolder* folder ) const
01275 {
01276   KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
01277   bool hide = dimapFolder && mHideFolders
01278        && (int)dimapFolder->account()->id() == GlobalSettings::self()->theIMAPResourceAccount()
01279        && GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount();
01280   return hide;
01281 
01282 }
01283 
01284 KFolderTreeItem::Type KMailICalIfaceImpl::folderType( KMFolder* folder ) const
01285 {
01286   if( mUseResourceIMAP && folder ) {
01287     if( folder == mCalendar || folder == mContacts
01288         || folder == mNotes || folder == mTasks
01289         || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01290       KMail::FolderContentsType ct = folder->storage()->contentsType();
01291       return s_folderContentsType[ct].treeItemType;
01292     }
01293   }
01294 
01295   return KFolderTreeItem::Other;
01296 }
01297 
01298 // Global tables of foldernames is different languages
01299 // For now: 0->English, 1->German, 2->French, 3->Dutch
01300 static TQMap<KFolderTreeItem::Type,TQString> folderNames[4];
01301 TQString KMailICalIfaceImpl::folderName( KFolderTreeItem::Type type, int language ) const
01302 {
01303   // With the XML storage, folders are always (internally) named in English
01304   if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
01305     language = 0;
01306 
01307   static bool folderNamesSet = false;
01308   if( !folderNamesSet ) {
01309     folderNamesSet = true;
01310     /* NOTE: If you add something here, you also need to update
01311        GroupwarePage in configuredialog.cpp */
01312 
01313     // English
01314     folderNames[0][KFolderTreeItem::Calendar] = TQString::fromLatin1("Calendar");
01315     folderNames[0][KFolderTreeItem::Tasks] = TQString::fromLatin1("Tasks");
01316     folderNames[0][KFolderTreeItem::Journals] = TQString::fromLatin1("Journal");
01317     folderNames[0][KFolderTreeItem::Contacts] = TQString::fromLatin1("Contacts");
01318     folderNames[0][KFolderTreeItem::Notes] = TQString::fromLatin1("Notes");
01319 
01320     // German
01321     folderNames[1][KFolderTreeItem::Calendar] = TQString::fromLatin1("Kalender");
01322     folderNames[1][KFolderTreeItem::Tasks] = TQString::fromLatin1("Aufgaben");
01323     folderNames[1][KFolderTreeItem::Journals] = TQString::fromLatin1("Journal");
01324     folderNames[1][KFolderTreeItem::Contacts] = TQString::fromLatin1("Kontakte");
01325     folderNames[1][KFolderTreeItem::Notes] = TQString::fromLatin1("Notizen");
01326 
01327     // French
01328     folderNames[2][KFolderTreeItem::Calendar] = TQString::fromLatin1("Calendrier");
01329     // Tasks = Tâches (â == 0xE2 in latin1)
01330     folderNames[2][KFolderTreeItem::Tasks] = TQString::fromLatin1("T\342ches");
01331     folderNames[2][KFolderTreeItem::Journals] = TQString::fromLatin1("Journal");
01332     folderNames[2][KFolderTreeItem::Contacts] = TQString::fromLatin1("Contacts");
01333     folderNames[2][KFolderTreeItem::Notes] = TQString::fromLatin1("Notes");
01334 
01335     // Dutch
01336     folderNames[3][KFolderTreeItem::Calendar] = TQString::fromLatin1("Agenda");
01337     folderNames[3][KFolderTreeItem::Tasks] = TQString::fromLatin1("Taken");
01338     folderNames[3][KFolderTreeItem::Journals] = TQString::fromLatin1("Logboek");
01339     folderNames[3][KFolderTreeItem::Contacts] = TQString::fromLatin1("Contactpersonen");
01340     folderNames[3][KFolderTreeItem::Notes] = TQString::fromLatin1("Notities");
01341   }
01342 
01343   if( language < 0 || language > 3 ) {
01344     return folderNames[mFolderLanguage][type];
01345   }
01346   else {
01347     return folderNames[language][type];
01348   }
01349 }
01350 
01351 
01352 // Find message matching a given UID
01353 KMMessage *KMailICalIfaceImpl::findMessageByUID( const TQString& uid, KMFolder* folder )
01354 {
01355   if( !folder || !mUIDToSerNum.contains( uid ) ) return 0;
01356   int i;
01357   KMFolder *aFolder;
01358   KMMsgDict::instance()->getLocation( mUIDToSerNum[uid], &aFolder, &i );
01359   Q_ASSERT( aFolder == folder );
01360   return folder->getMsg( i );
01361 }
01362 
01363 // Find message matching a given serial number
01364 KMMessage *KMailICalIfaceImpl::findMessageBySerNum( TQ_UINT32 serNum, KMFolder* folder )
01365 {
01366   if( !folder ) return 0;
01367 
01368   KMMessage *message = 0;
01369   KMFolder* aFolder = 0;
01370   int index;
01371   KMMsgDict::instance()->getLocation( serNum, &aFolder, &index );
01372 
01373   if( aFolder && aFolder != folder ) {
01374     kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) found it in folder " << aFolder->location() << ", expected " << folder->location() << endl;
01375   } else {
01376     if( aFolder )
01377       message = aFolder->getMsg( index );
01378     if (!message)
01379       kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) invalid serial number\n" << endl;
01380   }
01381   return message;
01382 }
01383 
01384 void KMailICalIfaceImpl::deleteMsg( KMMessage *msg )
01385 {
01386   if( !msg ) return;
01387   // Commands are now delayed; can't use that anymore, we need immediate deletion
01388   //( new KMDeleteMsgCommand( msg->parent(), msg ) )->start();
01389   KMFolder *srcFolder = msg->parent();
01390   int idx = srcFolder->find(msg);
01391   assert(idx != -1);
01392   // kill existing jobs since we are about to delete the message
01393   srcFolder->ignoreJobsForMessage( msg );
01394   if ( !msg->transferInProgress() ) {
01395     srcFolder->removeMsg(idx);
01396     delete msg;
01397   } else {
01398     kdDebug(5006) << k_funcinfo << "Message cannot be deleted now because it is currently in use " << msg << endl;
01399     msg->deleteWhenUnused();
01400   }
01401   addFolderChange( srcFolder, Contents );
01402 }
01403 
01404 void KMailICalIfaceImpl::folderContentsTypeChanged( KMFolder* folder,
01405                                                     KMail::FolderContentsType contentsType )
01406 {
01407   if ( !mUseResourceIMAP )
01408     return;
01409 //  kdDebug(5006) << "folderContentsTypeChanged( " << folder->name()
01410 //                << ", " << contentsType << ")\n";
01411 
01412   // The builtins can't change type
01413   if ( isStandardResourceFolder( folder ) )
01414     return;
01415 
01416   // Check if already know that 'extra folder'
01417   const TQString location = folder->location();
01418   ExtraFolder* ef = mExtraFolders.find( location );
01419   if ( ef && ef->folder ) {
01420     // Notify that the old folder resource is no longer available
01421     subresourceDeleted(folderContentsType( folder->storage()->contentsType() ), location );
01422 
01423     if ( contentsType == KMail::ContentsTypeMail ) {
01424       // Delete the old entry, stop listening and stop here
01425       mExtraFolders.remove( location );
01426       folder->disconnect( this );
01427       return;
01428     }
01429     // So the type changed to another groupware type, ok.
01430   } else {
01431     if ( ef && !ef->folder ) // deleted folder, clean up
01432       mExtraFolders.remove( location );
01433     if ( contentsType == KMail::ContentsTypeMail )
01434         return;
01435 
01436     //kdDebug(5006) << "registering " << location << " as extra folder" << endl;
01437     // Make a new entry for the list
01438     ef = new ExtraFolder( folder );
01439     mExtraFolders.insert( location, ef );
01440 
01441     FolderInfo info = readFolderInfo( folder );
01442     mFolderInfoMap.insert( folder, info );
01443 
01444     // Adjust the folder names of all foo.default folders.
01445     // German users will get Kalender as the name of all default Calendar folders,
01446     // including their own, so that the default calendar folder of their Japanese
01447     // coworker appears as /user/hirohito/Kalender, although Hirohito sees his folder
01448     // in Japanese. On the server the folders are always in English.
01449     if ( folder->folderType() == KMFolderTypeCachedImap ) {
01450       TQString annotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
01451       kdDebug(5006) << "folderContentsTypeChanged: " << folder->name() << " has annotation " << annotation << endl;
01452       if ( annotation == TQString( s_folderContentsType[contentsType].annotation ) + ".default" )
01453         folder->setLabel( localizedDefaultFolderName( contentsType ) );
01454     }
01455 
01456     connectFolder( folder );
01457   }
01458   // Tell about the new resource
01459   subresourceAdded( folderContentsType( contentsType ), location, subresourceLabelForPresentation(folder),
01460                     folder->isWritable(), folderIsAlarmRelevant( folder ) );
01461 }
01462 
01463 KMFolder* KMailICalIfaceImpl::extraFolder( const TQString& type,
01464                                            const TQString& folder )
01465 {
01466   // If an extra folder exists that matches the type and folder location,
01467   // use that
01468   int t = folderContentsType( type );
01469   if ( t < 1 || t > 5 )
01470     return 0;
01471 
01472   ExtraFolder* ef = mExtraFolders.find( folder );
01473   if ( ef && ef->folder && ef->folder->storage()->contentsType() == t )
01474     return ef->folder;
01475 
01476   return 0;
01477 }
01478 
01479 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( KMFolder* folder ) const
01480 {
01481   FolderInfoMap::ConstIterator it = mFolderInfoMap.find( folder );
01482   if ( it != mFolderInfoMap.end() )
01483     return (*it).mStorageFormat;
01484   return globalStorageFormat();
01485 }
01486 
01487 void KMailICalIfaceImpl::setStorageFormat( KMFolder* folder, StorageFormat format )
01488 {
01489   FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01490   if ( it != mFolderInfoMap.end() ) {
01491     (*it).mStorageFormat = format;
01492   } else {
01493     FolderInfo info( format, NoChange );
01494     mFolderInfoMap.insert( folder, info );
01495   }
01496   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01497   configGroup.writeEntry( folder->idString() + "-storageFormat",
01498                           format == StorageXML ? "xml" : "icalvcard" );
01499 }
01500 
01501 void KMailICalIfaceImpl::addFolderChange( KMFolder* folder, FolderChanges changes )
01502 {
01503   FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01504   if ( it != mFolderInfoMap.end() ) {
01505     (*it).mChanges = static_cast<FolderChanges>( (*it).mChanges | changes );
01506   } else { // Otherwise, well, it's a folder we don't care about.
01507     kdDebug(5006) << "addFolderChange: nothing known about folder " << folder->location() << endl;
01508   }
01509   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01510   configGroup.writeEntry( folder->idString() + "-changes", (*it).mChanges );
01511 }
01512 
01513 KMailICalIfaceImpl::FolderInfo KMailICalIfaceImpl::readFolderInfo( const KMFolder * const folder ) const
01514 {
01515   KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01516   TQString str = configGroup.readEntry( folder->idString() + "-storageFormat", "unset" );
01517   FolderInfo info;
01518   if ( str == "unset" ) {
01519     info.mStorageFormat = globalStorageFormat();
01520     configGroup.writeEntry( folder->idString() + "-storageFormat",
01521                             info.mStorageFormat == StorageXML ? "xml" : "icalvcard" );
01522   } else {
01523     info.mStorageFormat = ( str == "xml" ) ? StorageXML : StorageIcalVcard;
01524   }
01525   info.mChanges = (FolderChanges) configGroup.readNumEntry( folder->idString() + "-changes" );
01526   return info;
01527 }
01528 
01529 
01530 void KMailICalIfaceImpl::folderSynced( KMFolder* folder, const KURL& folderURL )
01531 {
01532   FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01533   if ( it != mFolderInfoMap.end() && (*it).mChanges ) {
01534     handleFolderSynced( folder, folderURL, (*it).mChanges );
01535     (*it).mChanges = NoChange;
01536   }
01537 }
01538 
01539 void KMailICalIfaceImpl::handleFolderSynced( KMFolder* folder,
01540                                              const KURL& folderURL,
01541                                              int _changes )
01542 {
01543   // This is done here instead of in the resource, because
01544   // there could be 0, 1, or N kolab resources at this point.
01545   // We can hack the N case, but not the 0 case.
01546   // So the idea of a DCOP signal for this wouldn't work.
01547   if ( ( _changes & KMailICalIface::Contents ) ||
01548        ( _changes & KMailICalIface::ACL ) ) {
01549     if ( storageFormat( folder ) == StorageXML && folder->storage()->contentsType() == KMail::ContentsTypeCalendar )
01550       triggerKolabFreeBusy( folderURL );
01551   }
01552 }
01553 
01554 void KMailICalIfaceImpl::folderDeletedOnServer( const KURL& folderURL )
01555 {
01556   triggerKolabFreeBusy( folderURL );
01557 }
01558 
01559 void KMailICalIfaceImpl::triggerKolabFreeBusy( const KURL& folderURL )
01560 {
01561   /* Steffen said: you must issue an authenticated HTTP GET request to
01562      https://kolabserver/freebusy/trigger/user@domain/Folder/NestedFolder.pfb
01563      (replace .pfb with .xpfb for extended fb lists). */
01564   KURL httpURL( folderURL );
01565   // Keep username ("user@domain"), pass, and host from the imap url
01566   httpURL.setProtocol( "https" );
01567   httpURL.setPort( 0 ); // remove imap port
01568 
01569   // IMAP path is either /INBOX/<path> or /user/someone/<path>
01570   TQString path = folderURL.path( -1 );
01571   Q_ASSERT( path.startsWith( "/" ) );
01572   int secondSlash = path.find( '/', 1 );
01573   if ( secondSlash == -1 ) {
01574     kdWarning() << "KCal::ResourceKolab::fromKMailFolderSynced path is too short: " << path << endl;
01575     return;
01576   }
01577   if ( path.startsWith( "/INBOX/", false ) ) {
01578     // If INBOX, replace it with the username (which is user@domain)
01579     path = path.mid( secondSlash );
01580     path.prepend( folderURL.user() );
01581   } else {
01582     // If user, just remove it. So we keep the IMAP-returned username.
01583     // This assumes it's a known user on the same domain.
01584     path = path.mid( secondSlash );
01585   }
01586 
01587   httpURL.setPath( "/freebusy/trigger/" + path + ".pfb" );
01588   httpURL.setQuery( TQString() );
01589   // Ensure that we encode everything with UTF8
01590   httpURL = KURL( httpURL.url(0,106), 106 );
01591   kdDebug() << "Triggering PFB update for " << folderURL << " : getting " << httpURL << endl;
01592   // "Fire and forget". No need for error handling, nor for explicit deletion.
01593   // Maybe we should try to prevent launching it if it's already running (for this URL) though.
01594   /*KIO::Job* job =*/ KIO::get( httpURL, false, false /*no progress info*/ );
01595 }
01596 
01597 void KMailICalIfaceImpl::slotFolderPropertiesChanged( KMFolder* folder )
01598 {
01599   if ( isResourceFolder( folder ) ) {
01600     const TQString location = folder->location();
01601     const TQString contentsTypeStr = folderContentsType( folder->storage()->contentsType() );
01602     subresourceDeleted( contentsTypeStr, location );
01603 
01604     subresourceAdded( contentsTypeStr, location, subresourceLabelForPresentation( folder ),
01605                       folder->isWritable(), folderIsAlarmRelevant( folder ) );
01606   }
01607 }
01608 
01609 // Must only be connected to a signal from KMFolder!
01610 void KMailICalIfaceImpl::slotFolderRenamed()
01611 {
01612   const KMFolder* folder = static_cast<const KMFolder *>( sender() );
01613   slotFolderPropertiesChanged( const_cast<KMFolder*>( folder ) );
01614 }
01615 
01616 void KMailICalIfaceImpl::slotFolderLocationChanged( const TQString &oldLocation,
01617                                                     const TQString &newLocation )
01618 {
01619   KMFolder *folder = findResourceFolder( oldLocation );
01620   ExtraFolder* ef = mExtraFolders.find( oldLocation );
01621   if ( ef ) {
01622     // reuse the ExtraFolder entry, but adjust the key
01623     mExtraFolders.setAutoDelete( false );
01624     mExtraFolders.remove( oldLocation );
01625     mExtraFolders.setAutoDelete( true );
01626     mExtraFolders.insert( newLocation, ef );
01627   }
01628   if (  folder )
01629     subresourceDeleted( folderContentsType(  folder->storage()->contentsType() ), oldLocation );
01630 
01631 }
01632 
01633 KMFolder* KMailICalIfaceImpl::findResourceFolder( const TQString& resource )
01634 {
01635   // Try the standard folders
01636   if( mCalendar && mCalendar->location() == resource )
01637     return mCalendar;
01638   if ( mContacts && mContacts->location() == resource )
01639     return mContacts;
01640   if ( mNotes && mNotes->location() == resource )
01641     return mNotes;
01642   if ( mTasks && mTasks->location() == resource )
01643     return mTasks;
01644   if ( mJournals && mJournals->location() == resource )
01645     return mJournals;
01646 
01647   // No luck. Try the extrafolders
01648   ExtraFolder* ef = mExtraFolders.find( resource );
01649   if ( ef )
01650     return ef->folder;
01651 
01652   // No luck at all
01653   return 0;
01654 }
01655 
01656 void KMailICalIfaceImpl::changeResourceUIName( const TQString &folderPath, const TQString &newName )
01657 {
01658   kdDebug() << "Folder path " << folderPath << endl;
01659   KMFolder *f = findResourceFolder( folderPath );
01660   if ( f ) {
01661     KMailICalIfaceImpl::getResourceMap()->insert( folderPath, newName );
01662     kmkernel->folderMgr()->renameFolder( f, newName );
01663     KConfigGroup configGroup( kmkernel->config(), "Resource UINames" );
01664     configGroup.writeEntry( folderPath, newName );
01665   }
01666 }
01667 
01668 // Builds a folder list from the dimap and the local folder list.
01669 static void createFolderList( TQStringList &folderNames, TQValueList<TQGuardedPtr<KMFolder> > &folderList )
01670 {
01671   TQStringList dimapFolderNames;
01672   TQStringList localFolderNames;
01673   TQValueList<TQGuardedPtr<KMFolder> > dimapFolderList;
01674   TQValueList<TQGuardedPtr<KMFolder> > localFolderList;
01675   kmkernel->dimapFolderMgr()->createFolderList( &dimapFolderNames, &dimapFolderList );
01676   kmkernel->folderMgr()->createFolderList( &localFolderNames, &localFolderList );
01677   folderNames += dimapFolderNames;
01678   folderNames += localFolderNames;
01679   folderList += dimapFolderList;
01680   folderList += localFolderList;
01681 }
01682 
01683 /****************************
01684  * The config stuff
01685  */
01686 
01687 void KMailICalIfaceImpl::readConfig()
01688 {
01689   bool enabled = GlobalSettings::self()->theIMAPResourceEnabled() &&
01690                  ( GlobalSettings::self()->theIMAPResourceAccount() != 0 );
01691 
01692   if( !enabled ) {
01693     if( mUseResourceIMAP == true ) {
01694       // Shutting down
01695       mUseResourceIMAP = false;
01696       cleanup();
01697       reloadFolderTree();
01698     }
01699     return;
01700   }
01701   mUseResourceIMAP = enabled;
01702 
01703   // Read remaining options
01704   const bool hideFolders = GlobalSettings::self()->hideGroupwareFolders();
01705   TQString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01706 
01707   // Find the folder parent
01708   KMFolderDir* folderParentDir;
01709   KMFolderType folderType;
01710   KMFolder* folderParent = kmkernel->findFolderById( parentName );
01711   if( folderParent == 0 ) {
01712     // Parent folder not found. It was probably deleted. The user will have to
01713     // configure things again.
01714     kdDebug(5006) << "Groupware folder " << parentName << " not found. Groupware functionality disabled" << endl;
01715     // Or maybe the inbox simply wasn't created on the first startup
01716     KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01717     Q_ASSERT( account );
01718     if ( account ) {
01719       // just in case we were connected already
01720       disconnect( account, TQT_SIGNAL( finishedCheck( bool, CheckStatus ) ),
01721                this, TQT_SLOT( slotCheckDone() ) );
01722       connect( account, TQT_SIGNAL( finishedCheck( bool, CheckStatus ) ),
01723                this, TQT_SLOT( slotCheckDone() ) );
01724     }
01725     mUseResourceIMAP = false;
01726     // We can't really call cleanup(), if those folders were completely deleted.
01727     mCalendar = 0;
01728     mTasks    = 0;
01729     mJournals = 0;
01730     mContacts = 0;
01731     mNotes    = 0;
01732     return;
01733   } else {
01734     folderParentDir = folderParent->createChildFolder();
01735     folderType = folderParent->folderType();
01736   }
01737 
01738   KMAcctCachedImap::GroupwareType groupwareType = dynamic_cast<KMFolderCachedImap *>( folderParent->storage() )->account()->groupwareType();
01739 
01740   if ( groupwareType == KMAcctCachedImap::GroupwareKolab ) {
01741     // Make sure the folder parent has the subdirs
01742     // Globally there are 3 cases: nothing found, some stuff found by type/name heuristics, or everything found OK
01743     bool noneFound = true;
01744     bool mustFix = false; // true when at least one was found by heuristics
01745     TQValueVector<StandardFolderSearchResult> results( KMail::ContentsTypeLast + 1 );
01746     for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01747       if ( i != KMail::ContentsTypeMail ) {
01748         results[i] = findStandardResourceFolder( folderParentDir, static_cast<KMail::FolderContentsType>(i) );
01749         if ( results[i].found == StandardFolderSearchResult::FoundAndStandard )
01750           noneFound = false;
01751         else if ( results[i].found == StandardFolderSearchResult::FoundByType ||
01752                   results[i].found == StandardFolderSearchResult::FoundByName ) {
01753           mustFix = true;
01754           noneFound = false;
01755         } else // NotFound
01756           mustFix = true;
01757       }
01758     }
01759 
01760     // Check if something changed
01761     if( mUseResourceIMAP && !noneFound && !mustFix && mFolderParentDir == folderParentDir
01762         && mFolderType == folderType ) {
01763       // Nothing changed
01764       if ( hideFolders != mHideFolders ) {
01765         // Well, the folder hiding has changed
01766         mHideFolders = hideFolders;
01767         reloadFolderTree();
01768       }
01769       return;
01770     }
01771 
01772     if( noneFound || mustFix ) {
01773       TQString msg;
01774       TQString parentFolderName = folderParent != 0 ? folderParent->name() : folderParentDir->name();
01775       if ( noneFound ) {
01776         // No subfolder was found, so ask if we can make them
01777         msg = i18n("KMail will now create the required groupware folders"
01778                    " as subfolders of %1; if you do not want this, cancel"
01779                    " and the IMAP resource will be disabled").arg(parentFolderName);
01780       } else {
01781         // Some subfolders were found, be more precise
01782         TQString operations = "<ul>";
01783         for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01784           if ( i != KMail::ContentsTypeMail ) {
01785             TQString typeName = localizedDefaultFolderName( static_cast<KMail::FolderContentsType>( i ) );
01786             if ( results[i].found == StandardFolderSearchResult::NotFound )
01787               operations += "<li>" + i18n( "%1: no folder found. It will be created." ).arg( typeName ) + "</li>";
01788             else if ( results[i].found == StandardFolderSearchResult::FoundByType || results[i].found == StandardFolderSearchResult::FoundByName )
01789               operations += "<li>" + i18n( "%1: found folder %2. It will be set as the main groupware folder." ).
01790                             arg( typeName ).arg( results[i].folder->label() ) + "</li>";
01791           }
01792         }
01793         operations += "</ul>";
01794 
01795         msg = i18n("<qt>KMail found the following groupware folders in %1 and needs to perform the following operations: %2"
01796                    "<br>If you do not want this, cancel"
01797                    " and the IMAP resource will be disabled").arg(parentFolderName, operations);
01798 
01799       }
01800 
01801       if( KMessageBox::questionYesNo( 0, msg,
01802                                       i18n("Standard Groupware Folders"), KStdGuiItem::cont(), KStdGuiItem::cancel() ) == KMessageBox::No ) {
01803 
01804         GlobalSettings::self()->setTheIMAPResourceEnabled( false );
01805         mUseResourceIMAP = false;
01806         mFolderParentDir = 0;
01807         mFolderParent = 0;
01808         reloadFolderTree();
01809         return;
01810       }
01811     }
01812 
01813     // Make the new settings work
01814     mUseResourceIMAP = true;
01815     mFolderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
01816     if( mFolderLanguage > 3 ) mFolderLanguage = 0;
01817     mFolderParentDir = folderParentDir;
01818     mFolderParent = folderParent;
01819     mFolderType = folderType;
01820     mHideFolders = hideFolders;
01821 
01822     // Close the previous folders
01823     cleanup();
01824 
01825     // Set the new folders
01826     mCalendar = initFolder( KMail::ContentsTypeCalendar );
01827     mTasks    = initFolder( KMail::ContentsTypeTask );
01828     mJournals = initFolder( KMail::ContentsTypeJournal );
01829     mContacts = initFolder( KMail::ContentsTypeContact );
01830     mNotes    = initFolder( KMail::ContentsTypeNote );
01831 
01832     // Store final annotation (with .default) so that we won't ask again on next startup
01833     if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01834       static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01835     if ( mTasks->folderType() == KMFolderTypeCachedImap )
01836       static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01837     if ( mJournals->folderType() == KMFolderTypeCachedImap )
01838       static_cast<KMFolderCachedImap *>( mJournals->storage() )->updateAnnotationFolderType();
01839     if ( mContacts->folderType() == KMFolderTypeCachedImap )
01840       static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01841     if ( mNotes->folderType() == KMFolderTypeCachedImap )
01842       static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01843 
01844     //kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
01845     //kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
01846     //kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
01847 
01848     // Find all extra folders
01849     TQStringList folderNames;
01850     TQValueList<TQGuardedPtr<KMFolder> > folderList;
01851     createFolderList( folderNames, folderList );
01852     for( TQValueList<TQGuardedPtr<KMFolder> >::iterator it = folderList.begin();
01853          it != folderList.end(); ++it )
01854     {
01855       FolderStorage *storage = (*it)->storage();
01856       KMFolderCachedImap* dimapStorage = dynamic_cast<KMFolderCachedImap*>( storage );
01857       if ( storage && storage->contentsType() != 0 ) {
01858         if ( dimapStorage )
01859           dimapStorage->updateAnnotationFolderType();
01860         folderContentsTypeChanged( *it, storage->contentsType() );
01861       }
01862     }
01863 
01864     // If we just created them, they might have been registered as extra folders temporarily.
01865     // -> undo that.
01866     mExtraFolders.remove( mCalendar->location() );
01867     mExtraFolders.remove( mTasks->location() );
01868     mExtraFolders.remove( mJournals->location() );
01869     mExtraFolders.remove( mContacts->location() );
01870     mExtraFolders.remove( mNotes->location() );
01871 
01872     subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
01873     subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
01874     subresourceAdded( folderContentsType( KMail::ContentsTypeJournal ), mJournals->location(), mJournals->label(), true, false );
01875     subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
01876     subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
01877   } else if ( groupwareType == KMAcctCachedImap::GroupwareScalix ) {
01878     // Make the new settings work
01879     mUseResourceIMAP = true;
01880     mFolderParentDir = folderParentDir;
01881     mFolderParent = folderParent;
01882     mFolderType = folderType;
01883     mHideFolders = false;
01884 
01885     // Close the previous folders
01886     cleanup();
01887 
01888     // Set the new folders
01889     mCalendar = initScalixFolder( KMail::ContentsTypeCalendar );
01890     mTasks    = initScalixFolder( KMail::ContentsTypeTask );
01891     mJournals = 0;
01892     mContacts = initScalixFolder( KMail::ContentsTypeContact );
01893     mNotes    = initScalixFolder( KMail::ContentsTypeNote );
01894 
01895     // Store final annotation (with .default) so that we won't ask again on next startup
01896     if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01897       static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01898     if ( mTasks->folderType() == KMFolderTypeCachedImap )
01899       static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01900     if ( mContacts->folderType() == KMFolderTypeCachedImap )
01901       static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01902     if ( mNotes->folderType() == KMFolderTypeCachedImap )
01903       static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01904 
01905     // BEGIN TILL TODO The below only uses the dimap folder manager, which
01906     // will fail for all other folder types. Adjust.
01907 
01908     kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
01909     kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
01910     kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
01911 
01912     // Find all extra folders
01913     TQStringList folderNames;
01914     TQValueList<TQGuardedPtr<KMFolder> > folderList;
01915     kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
01916     TQValueList<TQGuardedPtr<KMFolder> >::iterator it;
01917     for(it = folderList.begin(); it != folderList.end(); ++it)
01918     {
01919       FolderStorage *storage = (*it)->storage();
01920 
01921       if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
01922         KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
01923 
01924         const TQString attributes = imapFolder->folderAttributes();
01925         if ( attributes.contains( "X-FolderClass" ) ) {
01926           if ( !attributes.contains( "X-SpecialFolder" ) || (*it)->location().contains( "@" ) ) {
01927             const Scalix::FolderAttributeParser parser( attributes );
01928             if ( !parser.folderClass().isEmpty() ) {
01929               FolderContentsType type = Scalix::Utils::scalixIdToContentsType( parser.folderClass() );
01930               imapFolder->setContentsType( type );
01931               folderContentsTypeChanged( *it, type );
01932             }
01933           }
01934         }
01935       }
01936     }
01937 
01938     // If we just created them, they might have been registered as extra folders temporarily.
01939     // -> undo that.
01940     mExtraFolders.remove( mCalendar->location() );
01941     mExtraFolders.remove( mTasks->location() );
01942     mExtraFolders.remove( mContacts->location() );
01943     mExtraFolders.remove( mNotes->location() );
01944 
01945     // END TILL TODO
01946 
01947     subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
01948     subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
01949     subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
01950     subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
01951   }
01952 
01953   KConfig *config = kmkernel->config();
01954   config->setGroup("Resource UINames");
01955   *KMailICalIfaceImpl::mSubResourceUINamesMap =  config->entryMap( "Resource UINames" );
01956 
01957   reloadFolderTree();
01958 }
01959 
01960 void KMailICalIfaceImpl::slotCheckDone()
01961 {
01962   TQString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01963   KMFolder* folderParent = kmkernel->findFolderById( parentName );
01964   //kdDebug(5006) << k_funcinfo << " folderParent=" << folderParent << endl;
01965   if ( folderParent )  // cool it exists now
01966   {
01967     KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01968     if ( account )
01969       disconnect( account, TQT_SIGNAL( finishedCheck( bool, CheckStatus ) ),
01970                   this, TQT_SLOT( slotCheckDone() ) );
01971     readConfig();
01972   }
01973 }
01974 
01975 KMFolder* KMailICalIfaceImpl::initFolder( KMail::FolderContentsType contentsType )
01976 {
01977   // Figure out what type of folder this is supposed to be
01978   KMFolderType type = mFolderType;
01979   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
01980 
01981   KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
01982   //kdDebug(5006) << "KMailICalIfaceImpl::initFolder " << folderName( itemType ) << endl;
01983 
01984   // Find the folder
01985   StandardFolderSearchResult result = findStandardResourceFolder( mFolderParentDir, contentsType );
01986 
01987   // deal with multiple default groupware folders
01988   if ( result.folders.count() > 1 && result.found == StandardFolderSearchResult::FoundAndStandard ) {
01989     TQStringList labels;
01990     for ( TQValueList<KMFolder*>::ConstIterator it = result.folders.begin(); it != result.folders.end(); ++it )
01991       labels << (*it)->prettyURL();
01992     const TQString selected = KInputDialog::getItem( i18n("Default folder"),
01993         i18n("There are multiple %1 default folders, please choose one:")
01994         .arg( localizedDefaultFolderName( contentsType ) ), labels );
01995     if ( !selected.isEmpty() )
01996       result.folder = result.folders[ labels.findIndex( selected ) ];
01997   }
01998 
01999   KMFolder* folder = result.folder;
02000 
02001   if ( !folder ) {
02002     // The folder isn't there yet - create it
02003     folder =
02004       mFolderParentDir->createFolder( localizedDefaultFolderName( contentsType ), false, type );
02005     if( mFolderType == KMFolderTypeImap ) {
02006       KMFolderImap* parentFolder = static_cast<KMFolderImap*>( mFolderParent->storage() );
02007       parentFolder->createFolder( localizedDefaultFolderName( contentsType ) );
02008       static_cast<KMFolderImap*>( folder->storage() )->setAccount( parentFolder->account() );
02009     }
02010     // Groupware folder created, use the global setting for storage format
02011     setStorageFormat( folder, globalStorageFormat() );
02012   } else {
02013     FolderInfo info = readFolderInfo( folder );
02014     mFolderInfoMap.insert( folder, info );
02015     //kdDebug(5006) << "Found existing folder type " << itemType << " : " << folder->location()  << endl;
02016   }
02017 
02018   if( folder->canAccess() != 0 ) {
02019     KMessageBox::sorry(0, i18n("You do not have read/write permission to your %1 folder.")
02020                        .arg( folderName( itemType ) ) );
02021     return 0;
02022   }
02023   folder->storage()->setContentsType( contentsType );
02024   folder->setSystemFolder( true );
02025   folder->storage()->writeConfig();
02026   folder->open("ifacefolder");
02027   connectFolder( folder );
02028   return folder;
02029 }
02030 
02031 KMFolder* KMailICalIfaceImpl::initScalixFolder( KMail::FolderContentsType contentsType )
02032 {
02033   // Figure out what type of folder this is supposed to be
02034   KMFolderType type = mFolderType;
02035   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02036 
02037   KMFolder* folder = 0;
02038 
02039   // Find all extra folders
02040   TQStringList folderNames;
02041   TQValueList<TQGuardedPtr<KMFolder> > folderList;
02042   Q_ASSERT( kmkernel );
02043   Q_ASSERT( kmkernel->dimapFolderMgr() );
02044   kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
02045   TQValueList<TQGuardedPtr<KMFolder> >::iterator it = folderList.begin();
02046   for(; it != folderList.end(); ++it)
02047   {
02048     FolderStorage *storage = (*it)->storage();
02049 
02050     if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
02051       KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
02052 
02053       const TQString attributes = imapFolder->folderAttributes();
02054       if ( attributes.contains( "X-SpecialFolder" ) ) {
02055         const Scalix::FolderAttributeParser parser( attributes );
02056         if ( contentsType == Scalix::Utils::scalixIdToContentsType( parser.folderClass() ) ) {
02057           folder = *it;
02058           break;
02059         }
02060       }
02061     }
02062   }
02063 
02064   if ( !folder ) {
02065     return 0;
02066   } else {
02067     FolderInfo info = readFolderInfo( folder );
02068     mFolderInfoMap.insert( folder, info );
02069     //kdDebug(5006) << "Found existing folder type " << itemType << " : " << folder->location()  << endl;
02070   }
02071 
02072   if( folder->canAccess() != 0 ) {
02073     KMessageBox::sorry(0, i18n("You do not have read/write permission to your folder.") );
02074     return 0;
02075   }
02076   folder->storage()->setContentsType( contentsType );
02077   folder->setSystemFolder( true );
02078   folder->storage()->writeConfig();
02079   folder->open( "scalixfolder" );
02080   connectFolder( folder );
02081   return folder;
02082 }
02083 
02084 void KMailICalIfaceImpl::connectFolder( KMFolder* folder )
02085 {
02086   // avoid multiple connections
02087   disconnect( folder, TQT_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ),
02088               this, TQT_SLOT( slotIncidenceAdded( KMFolder*, TQ_UINT32 ) ) );
02089   disconnect( folder, TQT_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ),
02090               this, TQT_SLOT( slotIncidenceDeleted( KMFolder*, TQ_UINT32 ) ) );
02091   disconnect( folder, TQT_SIGNAL( expunged( KMFolder* ) ),
02092               this, TQT_SLOT( slotRefreshFolder( KMFolder* ) ) );
02093   disconnect( folder->storage(), TQT_SIGNAL( readOnlyChanged( KMFolder* ) ),
02094               this, TQT_SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
02095   disconnect( folder, TQT_SIGNAL( nameChanged() ),
02096               this, TQT_SLOT( slotFolderRenamed() ) );
02097   disconnect( folder->storage(), TQT_SIGNAL( locationChanged( const TQString&, const TQString&) ),
02098               this, TQT_SLOT( slotFolderLocationChanged( const TQString&, const TQString&) ) );
02099 
02100   // Setup the signals to listen for changes
02101   connect( folder, TQT_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ),
02102            this, TQT_SLOT( slotIncidenceAdded( KMFolder*, TQ_UINT32 ) ) );
02103   connect( folder, TQT_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ),
02104            this, TQT_SLOT( slotIncidenceDeleted( KMFolder*, TQ_UINT32 ) ) );
02105   connect( folder, TQT_SIGNAL( expunged( KMFolder* ) ),
02106            this, TQT_SLOT( slotRefreshFolder( KMFolder* ) ) );
02107   connect( folder->storage(), TQT_SIGNAL( readOnlyChanged( KMFolder* ) ),
02108            this, TQT_SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
02109   connect( folder, TQT_SIGNAL( nameChanged() ),
02110            this, TQT_SLOT( slotFolderRenamed() ) );
02111   connect( folder->storage(), TQT_SIGNAL( locationChanged( const TQString&, const TQString&) ),
02112            this, TQT_SLOT( slotFolderLocationChanged( const TQString&, const TQString&) ) );
02113 
02114 }
02115 
02116 static void cleanupFolder( KMFolder* folder, KMailICalIfaceImpl* _this )
02117 {
02118   if( folder ) {
02119     folder->setSystemFolder( false );
02120     folder->disconnect( _this );
02121     folder->close("ifacefolder");
02122   }
02123 }
02124 
02125 void KMailICalIfaceImpl::cleanup()
02126 {
02127   cleanupFolder( mContacts, this );
02128   cleanupFolder( mCalendar, this );
02129   cleanupFolder( mNotes, this );
02130   cleanupFolder( mTasks, this );
02131   cleanupFolder( mJournals, this );
02132 
02133   mContacts = mCalendar = mNotes = mTasks = mJournals = 0;
02134 }
02135 
02136 TQString KMailICalIfaceImpl::folderPixmap( KFolderTreeItem::Type type ) const
02137 {
02138   if( !mUseResourceIMAP )
02139     return TQString();
02140 
02141   if( type == KFolderTreeItem::Contacts )
02142     return TQString::fromLatin1( "kmgroupware_folder_contacts" );
02143   else if( type == KFolderTreeItem::Calendar )
02144     return TQString::fromLatin1( "kmgroupware_folder_calendar" );
02145   else if( type == KFolderTreeItem::Notes )
02146     return TQString::fromLatin1( "kmgroupware_folder_notes" );
02147   else if( type == KFolderTreeItem::Tasks )
02148     return TQString::fromLatin1( "kmgroupware_folder_tasks" );
02149   else if( type == KFolderTreeItem::Journals )
02150     return TQString::fromLatin1( "kmgroupware_folder_journals" );
02151 
02152   return TQString();
02153 }
02154 
02155 static void reloadFolderTree()
02156 {
02157   // Make the folder tree show the icons or not
02158   kmkernel->folderMgr()->contentsChanged();
02159 }
02160 
02161 // This is a very light-weight and fast 'parser' to retrieve
02162 // a data entry from a vCal taking continuation lines
02163 // into account
02164 static void vPartMicroParser( const TQString& str, TQString& s )
02165 {
02166   TQString line;
02167   uint len = str.length();
02168 
02169   for( uint i=0; i<len; ++i){
02170     if( str[i] == '\r' || str[i] == '\n' ){
02171       if( str[i] == '\r' )
02172         ++i;
02173       if( i+1 < len && str[i+1] == ' ' ){
02174         // found a continuation line, skip it's leading blanc
02175         ++i;
02176       }else{
02177         // found a logical line end, process the line
02178         if( line.startsWith( s ) ) {
02179           s = line.mid( s.length() + 1 );
02180           return;
02181         }
02182         line = "";
02183       }
02184     } else {
02185       line += str[i];
02186     }
02187   }
02188 
02189   // Not found. Clear it
02190   s.truncate(0);
02191 }
02192 
02193 // Returns the first child folder having the given annotation
02194 static TQValueList<KMFolder*> findFolderByAnnotation( KMFolderDir* folderParentDir, const TQString& annotation )
02195 {
02196   TQValueList<KMFolder*> rv;
02197   TQPtrListIterator<KMFolderNode> it( *folderParentDir );
02198   for ( ; it.current(); ++it ) {
02199     if ( !it.current()->isDir() ) {
02200       KMFolder* folder = static_cast<KMFolder *>( it.current() );
02201       if ( folder->folderType() == KMFolderTypeCachedImap ) {
02202         TQString folderAnnotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
02203         //kdDebug(5006) << "findStandardResourceFolder: " << folder->name() << " has annotation " << folderAnnotation << endl;
02204         if ( folderAnnotation == annotation )
02205           rv.append( folder );
02206       }
02207     }
02208   }
02209   return rv;
02210 }
02211 
02212 KMailICalIfaceImpl::StandardFolderSearchResult KMailICalIfaceImpl::findStandardResourceFolder( KMFolderDir* folderParentDir, KMail::FolderContentsType contentsType )
02213 {
02214   if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
02215   {
02216     // Look for a folder with an annotation like "event.default"
02217     TQValueList<KMFolder*> folders = findFolderByAnnotation( folderParentDir, TQString( s_folderContentsType[contentsType].annotation ) + ".default" );
02218     if ( !folders.isEmpty() )
02219       return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundAndStandard );
02220 
02221     // Fallback: look for a folder with an annotation like "event"
02222     folders = findFolderByAnnotation( folderParentDir, TQString( s_folderContentsType[contentsType].annotation ) );
02223     if ( !folders.isEmpty() )
02224       return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundByType );
02225 
02226     // Fallback: look for the folder by name (we'll need to change its type)
02227     KMFolderNode* node = folderParentDir->hasNamedFolder( localizedDefaultFolderName( contentsType ) );
02228     if ( node && !node->isDir() )
02229       return StandardFolderSearchResult( static_cast<KMFolder *>( node ), StandardFolderSearchResult::FoundByName );
02230 
02231     kdDebug(5006) << "findStandardResourceFolder: found no resource folder for " << s_folderContentsType[contentsType].annotation << endl;
02232     return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02233   }
02234   else // icalvcard: look up standard resource folders by name
02235   {
02236     KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
02237     unsigned int folderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
02238     if( folderLanguage > 3 ) folderLanguage = 0;
02239     KMFolderNode* node = folderParentDir->hasNamedFolder( folderName( itemType, folderLanguage ) );
02240     if ( !node || node->isDir() )
02241       return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
02242     return StandardFolderSearchResult( static_cast<KMFolder*>( node ), StandardFolderSearchResult::FoundAndStandard );
02243   }
02244 }
02245 
02246 /* We treat all folders as relevant wrt alarms for which we have Administer
02247  * rights or for which the "Incidences relevant for everyone" annotation has
02248  * been set. It can be reasonably assumed that those are "ours". All local folders
02249  * must be ours anyhow. */
02250 bool KMailICalIfaceImpl::folderIsAlarmRelevant( const KMFolder *folder )
02251 {
02252   bool administerRights = true;
02253   bool relevantForOwner = true;
02254   bool relevantForEveryone = false;
02255   if ( folder->folderType() == KMFolderTypeImap ) {
02256     const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
02257     administerRights =
02258       imapFolder->userRightsState() != KMail::ACLJobs::Ok ||
02259       imapFolder->userRights() & KMail::ACLJobs::Administer;
02260   }
02261   if ( folder->folderType() == KMFolderTypeCachedImap ) {
02262     const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
02263     administerRights =
02264       dimapFolder->userRightsState() != KMail::ACLJobs::Ok ||
02265       dimapFolder->userRights() & KMail::ACLJobs::Administer;
02266     relevantForOwner = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor () == KMFolderCachedImap::IncForAdmins );
02267     relevantForEveryone = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor() == KMFolderCachedImap::IncForReaders );
02268   }
02269 #if 0
02270   kdDebug(5006) << k_funcinfo << endl;
02271   kdDebug(5006) << "Folder: " << folder->label() << " has administer rights: " << administerRights << endl;
02272   kdDebug(5006) << "and is relevant for owner: " << relevantForOwner <<  endl;
02273   kdDebug(5006) << "and relevant for everyone: "  << relevantForEveryone << endl;
02274 #endif
02275   return ( administerRights && relevantForOwner ) || relevantForEveryone;
02276 }
02277 
02278 void KMailICalIfaceImpl::setResourceQuiet(bool q)
02279 {
02280   mResourceQuiet = q;
02281 }
02282 
02283 bool KMailICalIfaceImpl::isResourceQuiet() const
02284 {
02285   return mResourceQuiet;
02286 }
02287 
02288 
02289 bool KMailICalIfaceImpl::addSubresource( const TQString& resource,
02290                                          const TQString& parent,
02291                                          const TQString& contentsType )
02292 {
02293   kdDebug(5006) << "Adding subresource to parent: " << parent << " with name: " << resource << endl;
02294   kdDebug(5006) << "contents type: " << contentsType << endl;
02295   KMFolder *folder = findResourceFolder( parent );
02296   KMFolderDir *parentFolderDir = !parent.isEmpty() && folder ? folder->createChildFolder(): mFolderParentDir;
02297   if ( !parentFolderDir || parentFolderDir->hasNamedFolder( resource ) ) return false;
02298 
02299   TQString msg;
02300   if ( parentFolderDir->owner() && !parentFolderDir->owner()->isValidName( resource, msg ) ) {
02301     KMessageBox::error( 0, msg );
02302     return false;
02303   }
02304 
02305   KMFolderType type = mFolderType;
02306   if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
02307 
02308   KMFolder* newFolder = parentFolderDir->createFolder( resource, false, type );
02309   if ( !newFolder ) return false;
02310   if( mFolderType == KMFolderTypeImap )
02311     static_cast<KMFolderImap*>( folder->storage() )->createFolder( resource );
02312 
02313   StorageFormat defaultFormat = GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
02314   setStorageFormat( newFolder, folder ? storageFormat( folder ) : defaultFormat );
02315   newFolder->storage()->setContentsType( folderContentsType( contentsType ) );
02316   newFolder->storage()->writeConfig();
02317   newFolder->open( "ical_subresource" );
02318   connectFolder( newFolder );
02319   reloadFolderTree();
02320 
02321   return true;
02322 }
02323 
02324 bool KMailICalIfaceImpl::removeSubresource( const TQString& location )
02325 {
02326   kdDebug(5006) << k_funcinfo << endl;
02327 
02328   KMFolder *folder = findResourceFolder( location );
02329 
02330   // We don't allow the default folders to be deleted, so check for
02331   // those first. It would be nicer to produce a more meaningful error,
02332   // or prevent deletion of the builtin folders from the gui already.
02333   if ( !folder || isStandardResourceFolder( folder ) )
02334       return false;
02335 
02336   // the folder will be removed, which implies closed, so make sure
02337   // nothing is using it anymore first
02338   subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), location );
02339   mExtraFolders.remove( location );
02340   folder->disconnect( this );
02341 
02342   if ( folder->folderType() == KMFolderTypeImap )
02343     kmkernel->imapFolderMgr()->remove( folder );
02344   else if ( folder->folderType() == KMFolderTypeCachedImap ) {
02345     // Deleted by user -> tell the account (see KMFolderCachedImap::listDirectory2)
02346     KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( folder->storage() );
02347     KMAcctCachedImap* acct = storage->account();
02348     if ( acct )
02349       acct->addDeletedFolder( folder );
02350     kmkernel->dimapFolderMgr()->remove( folder );
02351   }
02352   return true;
02353 }
02354 
02355 void KMailICalIfaceImpl::syncFolder(KMFolder * folder) const
02356 {
02357   if ( kmkernel->isOffline() || !GlobalSettings::immediatlySyncDIMAPOnGroupwareChanges() )
02358     return;
02359   KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
02360   if ( !dimapFolder )
02361     return;
02362   // check if the folder exists already, otherwise sync its parent as well to create it
02363   if ( dimapFolder->imapPath().isEmpty() ) {
02364     if ( folder->parent() && folder->parent()->owner() )
02365       syncFolder( folder->parent()->owner() );
02366     else
02367       return;
02368   }
02369   dimapFolder->account()->processNewMailInFolder( folder );
02370 }
02371 
02372 #include "kmailicalifaceimpl.moc"