kmail

kmailicalifaceimpl.cpp

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