00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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 using namespace KMail;
00074
00075
00076 static void vPartMicroParser( const QString& str, QString& s );
00077 static void reloadFolderTree();
00078
00079
00080 static const struct {
00081 const char* contentsTypeStr;
00082 const char* mimetype;
00083 KFolderTreeItem::Type treeItemType;
00084 const char* annotation;
00085 const char* translatedName;
00086 } s_folderContentsType[] = {
00087 { "Mail", "application/x-vnd.kolab.mail", KFolderTreeItem::Other, "mail", I18N_NOOP( "Mail" ) },
00088 { "Calendar", "application/x-vnd.kolab.event", KFolderTreeItem::Calendar, "event", I18N_NOOP( "Calendar" ) },
00089 { "Contact", "application/x-vnd.kolab.contact", KFolderTreeItem::Contacts, "contact", I18N_NOOP( "Contacts" ) },
00090 { "Note", "application/x-vnd.kolab.note", KFolderTreeItem::Notes, "note", I18N_NOOP( "Notes" ) },
00091 { "Task", "application/x-vnd.kolab.task", KFolderTreeItem::Tasks, "task", I18N_NOOP( "Tasks" ) },
00092 { "Journal", "application/x-vnd.kolab.journal", KFolderTreeItem::Journals, "journal", I18N_NOOP( "Journal" ) }
00093 };
00094
00095 static QString folderContentsType( KMail::FolderContentsType type )
00096 {
00097 return s_folderContentsType[type].contentsTypeStr;
00098 }
00099
00100 static QString folderKolabMimeType( KMail::FolderContentsType type )
00101 {
00102 return s_folderContentsType[type].mimetype;
00103 }
00104
00105 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::globalStorageFormat() const {
00106 return GlobalSettings::self()->theIMAPResourceStorageFormat()
00107 == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
00108 }
00109
00110 static KMail::FolderContentsType folderContentsType( const QString& type )
00111 {
00112 for ( uint i = 0 ; i < sizeof s_folderContentsType / sizeof *s_folderContentsType; ++i )
00113 if ( type == s_folderContentsType[i].contentsTypeStr )
00114 return static_cast<KMail::FolderContentsType>( i );
00115 return KMail::ContentsTypeMail;
00116 }
00117
00118 static QString localizedDefaultFolderName( KMail::FolderContentsType type )
00119 {
00120 return i18n( s_folderContentsType[type].translatedName );
00121 }
00122
00123 const char* KMailICalIfaceImpl::annotationForContentsType( KMail::FolderContentsType type )
00124 {
00125 return s_folderContentsType[type].annotation;
00126 }
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138 KMailICalIfaceImpl::KMailICalIfaceImpl()
00139 : DCOPObject( "KMailICalIface" ), QObject( 0, "KMailICalIfaceImpl" ),
00140 mContacts( 0 ), mCalendar( 0 ), mNotes( 0 ), mTasks( 0 ), mJournals( 0 ),
00141 mFolderLanguage( 0 ), mFolderParentDir( 0 ), mFolderType( KMFolderTypeUnknown ),
00142 mUseResourceIMAP( false ), mResourceQuiet( false ), mHideFolders( true )
00143 {
00144
00145 connect( kmkernel, SIGNAL( configChanged() ), this, SLOT( readConfig() ) );
00146 connect( kmkernel, SIGNAL( folderRemoved( KMFolder* ) ),
00147 this, SLOT( slotFolderRemoved( KMFolder* ) ) );
00148
00149 mExtraFolders.setAutoDelete( true );
00150 mAccumulators.setAutoDelete( true );
00151 }
00152
00153
00154
00155
00156
00157
00158
00159 static DwBodyPart* findBodyPartByMimeType( const KMMessage& msg, const char* sType, const char* sSubtype, bool startsWith = false )
00160 {
00161
00162
00163 DwBodyPart* part = msg.getFirstDwBodyPart();
00164 while( part ){
00165
00166
00167 if ( part->hasHeaders() ) {
00168 DwMediaType& contentType = part->Headers().ContentType();
00169 if ( startsWith ) {
00170 if ( contentType.TypeStr() == sType
00171 && QString( contentType.SubtypeStr().c_str() ).startsWith( sSubtype ) )
00172 return part;
00173 }
00174 else
00175 if ( contentType.TypeStr() == sType
00176 && contentType.SubtypeStr() == sSubtype )
00177 return part;
00178 }
00179 part = part->Next();
00180 }
00181 return 0;
00182 }
00183
00184
00185 static DwBodyPart* findBodyPart( const KMMessage& msg, const QString& attachmentName )
00186 {
00187
00188
00189 for ( DwBodyPart* part = msg.getFirstDwBodyPart(); part; part = part->Next() ) {
00190
00191 if ( part->hasHeaders()
00192 && attachmentName == part->Headers().ContentDisposition().Filename().c_str() )
00193 return part;
00194 }
00195 return 0;
00196 }
00197
00198 #if 0
00199 static void debugBodyParts( const char* foo, const KMMessage& msg )
00200 {
00201 kdDebug(5006) << "--debugBodyParts " << foo << "--" << endl;
00202 for ( DwBodyPart* part = msg.getFirstDwBodyPart(); part; part = part->Next() ) {
00203 if ( part->hasHeaders() ) {
00204 kdDebug(5006) << " bodypart: " << part << endl;
00205 kdDebug(5006) << " " << part->Headers().AsString().c_str() << endl;
00206 }
00207 else
00208 kdDebug(5006) << " part " << part << " has no headers" << endl;
00209 }
00210 }
00211 #else
00212 inline static void debugBodyParts( const char*, const KMMessage& ) {}
00213 #endif
00214
00215
00216
00217
00218
00219
00220 bool KMailICalIfaceImpl::updateAttachment( KMMessage& msg,
00221 const QString& attachmentURL,
00222 const QString& attachmentName,
00223 const QString& attachmentMimetype,
00224 bool lookupByName )
00225 {
00226 kdDebug(5006) << "KMailICalIfaceImpl::updateAttachment( " << attachmentURL << " )" << endl;
00227
00228 bool bOK = false;
00229
00230 KURL url( attachmentURL );
00231 if ( url.isValid() && url.isLocalFile() ) {
00232 const QString fileName( url.path() );
00233 QFile file( fileName );
00234 if( file.open( IO_ReadOnly ) ) {
00235 QByteArray rawData = file.readAll();
00236 file.close();
00237
00238
00239 KMMessagePart msgPart;
00240 msgPart.setName( attachmentName );
00241
00242 const int iSlash = attachmentMimetype.find('/');
00243 const QCString sType = attachmentMimetype.left( iSlash ).latin1();
00244 const QCString sSubtype = attachmentMimetype.mid( iSlash+1 ).latin1();
00245 msgPart.setTypeStr( sType );
00246 msgPart.setSubtypeStr( sSubtype );
00247 QCString ctd("attachment;\n filename=\"");
00248 ctd.append( attachmentName.latin1() );
00249 ctd.append("\"");
00250 msgPart.setContentDisposition( ctd );
00251 QValueList<int> dummy;
00252 msgPart.setBodyAndGuessCte( rawData, dummy );
00253 msgPart.setPartSpecifier( fileName );
00254
00255 DwBodyPart* newPart = msg.createDWBodyPart( &msgPart );
00256
00257
00258
00259 newPart->Headers().ContentDisposition().Parse();
00260
00261 DwBodyPart* part = lookupByName ? findBodyPart( msg, attachmentName )
00262 : findBodyPartByMimeType( msg, sType, sSubtype );
00263 if ( part ) {
00264
00265
00266 newPart->SetNext( part->Next() );
00267
00268
00269 *part = *newPart;
00270 delete newPart;
00271 msg.setNeedsAssembly();
00272 kdDebug(5006) << "Attachment " << attachmentName << " updated." << endl;
00273 } else {
00274 msg.addDwBodyPart( newPart );
00275 kdDebug(5006) << "Attachment " << attachmentName << " added." << endl;
00276 }
00277 bOK = true;
00278 }else{
00279 kdDebug(5006) << "Attachment " << attachmentURL << " can not be read." << endl;
00280 }
00281 }else{
00282 kdDebug(5006) << "Attachment " << attachmentURL << " not a local file." << endl;
00283 }
00284
00285 return bOK;
00286 }
00287
00288
00289 bool KMailICalIfaceImpl::kolabXMLFoundAndDecoded( const KMMessage& msg, const QString& mimetype, QString& s )
00290 {
00291 const int iSlash = mimetype.find('/');
00292 const QCString sType = mimetype.left( iSlash ).latin1();
00293 const QCString sSubtype = mimetype.mid( iSlash+1 ).latin1();
00294 DwBodyPart* part = findBodyPartByMimeType( msg, sType, sSubtype, true );
00295 if ( part ) {
00296 KMMessagePart msgPart;
00297 KMMessage::bodyPart(part, &msgPart);
00298 s = msgPart.bodyToUnicode( QTextCodec::codecForName( "utf8" ) );
00299 return true;
00300 }
00301 return false;
00302 }
00303
00304
00305
00306
00307
00308
00309
00310 bool KMailICalIfaceImpl::deleteAttachment( KMMessage& msg,
00311 const QString& attachmentName )
00312 {
00313 kdDebug(5006) << "KMailICalIfaceImpl::deleteAttachment( " << attachmentName << " )" << endl;
00314
00315 bool bOK = false;
00316
00317
00318
00319 DwBodyPart* part = findBodyPart( msg, attachmentName );
00320 if ( part ) {
00321 msg.getTopLevelPart()->Body().RemoveBodyPart( part );
00322 delete part;
00323 msg.setNeedsAssembly();
00324 kdDebug(5006) << "Attachment deleted." << endl;
00325 bOK = true;
00326 }
00327
00328 if( !bOK ){
00329 kdDebug(5006) << "Attachment " << attachmentName << " not found." << endl;
00330 }
00331
00332 return bOK;
00333 }
00334
00335 static void setIcalVcardContentTypeHeader( KMMessage *msg, KMail::FolderContentsType t )
00336 {
00337 msg->setType( DwMime::kTypeText );
00338 if ( t == KMail::ContentsTypeCalendar || t == KMail::ContentsTypeTask
00339 || t == KMail::ContentsTypeJournal ) {
00340 msg->setSubtype( DwMime::kSubtypeVCal );
00341 msg->setHeaderField("Content-Type",
00342 "text/calendar; method=REQUEST; charset=\"utf-8\"");
00343 } else if ( t == KMail::ContentsTypeContact ) {
00344 msg->setSubtype( DwMime::kSubtypeXVCard );
00345 msg->setHeaderField( "Content-Type", "Text/X-VCard; charset=\"utf-8\"" );
00346 } else {
00347 kdWarning(5006) << k_funcinfo << "Attempt to write non-groupware contents to folder" << endl;
00348 }
00349 }
00350
00351 static void setXMLContentTypeHeader( KMMessage *msg, const QString plainTextBody )
00352 {
00353
00354
00355
00356 KMMessagePart firstPart;
00357 firstPart.setType( DwMime::kTypeText );
00358 firstPart.setSubtype( DwMime::kSubtypePlain );
00359 msg->removeHeaderField( "Content-Type" );
00360 msg->setType( DwMime::kTypeMultipart );
00361 msg->setSubtype( DwMime::kSubtypeMixed );
00362 msg->headers().ContentType().CreateBoundary( 0 );
00363 msg->headers().ContentType().Assemble();
00364 firstPart.setBodyFromUnicode( plainTextBody );
00365 msg->addBodyPart( &firstPart );
00366 }
00367
00368
00369 Q_UINT32 KMailICalIfaceImpl::addIncidenceKolab( KMFolder& folder,
00370 const QString& subject,
00371 const QString& plainTextBody,
00372 const QMap<QCString, QString>& customHeaders,
00373 const QStringList& attachmentURLs,
00374 const QStringList& attachmentNames,
00375 const QStringList& attachmentMimetypes )
00376 {
00377 kdDebug(5006) << "KMailICalIfaceImpl::addIncidenceKolab( " << attachmentNames << " )" << endl;
00378
00379 Q_UINT32 sernum = 0;
00380 bool bAttachOK = true;
00381
00382
00383 KMMessage* msg = new KMMessage();
00384 msg->initHeader();
00385 msg->setSubject( subject );
00386 msg->setAutomaticFields( true );
00387
00388 QMap<QCString, QString>::ConstIterator ith = customHeaders.begin();
00389 const QMap<QCString, QString>::ConstIterator ithEnd = customHeaders.end();
00390 for ( ; ith != ithEnd ; ++ith ) {
00391 msg->setHeaderField( ith.key(), ith.data() );
00392 }
00393
00394
00395 if ( storageFormat( &folder ) == StorageXML ) {
00396 setXMLContentTypeHeader( msg, plainTextBody );
00397 } else if ( storageFormat( &folder ) == StorageIcalVcard ) {
00398 const KMail::FolderContentsType t = folder.storage()->contentsType();
00399 setIcalVcardContentTypeHeader( msg, t );
00400 msg->setBodyEncoded( plainTextBody.utf8() );
00401 } else {
00402 kdWarning(5006) << k_funcinfo << "Attempt to write to folder with unknown storage type" << endl;
00403 }
00404
00405 Q_ASSERT( attachmentMimetypes.count() == attachmentURLs.count() );
00406 Q_ASSERT( attachmentNames.count() == attachmentURLs.count() );
00407
00408 QStringList::ConstIterator itmime = attachmentMimetypes.begin();
00409 QStringList::ConstIterator iturl = attachmentURLs.begin();
00410 for( QStringList::ConstIterator itname = attachmentNames.begin();
00411 itname != attachmentNames.end()
00412 && itmime != attachmentMimetypes.end()
00413 && iturl != attachmentURLs.end();
00414 ++itname, ++iturl, ++itmime ){
00415 bool bymimetype = (*itmime).startsWith( "application/x-vnd.kolab." );
00416 if( !updateAttachment( *msg, *iturl, *itname, *itmime, !bymimetype ) ){
00417 kdWarning(5006) << "Attachment error, can not add Incidence." << endl;
00418 bAttachOK = false;
00419 break;
00420 }
00421 }
00422
00423 if( bAttachOK ){
00424
00425 msg->cleanupHeader();
00426
00427 msg->touch();
00428 if ( folder.addMsg( msg ) == 0 )
00429
00430 sernum = msg->getMsgSerNum();
00431 kdDebug(5006) << "addIncidenceKolab(): Message done and saved. Sernum: "
00432 << sernum << endl;
00433
00434
00435 addFolderChange( &folder, Contents );
00436 } else
00437 kdError(5006) << "addIncidenceKolab(): Message *NOT* saved!\n";
00438
00439 return sernum;
00440 }
00441
00442 bool KMailICalIfaceImpl::deleteIncidenceKolab( const QString& resource,
00443 Q_UINT32 sernum )
00444 {
00445
00446 if( !mUseResourceIMAP )
00447 return false;
00448
00449 kdDebug(5006) << "KMailICalIfaceImpl::deleteIncidenceKolab( "
00450 << resource << ", " << sernum << ")\n";
00451
00452
00453 KMFolder* f = findResourceFolder( resource );
00454 if( !f ) {
00455 kdError(5006) << "deleteIncidenceKolab(" << resource << ") : Not an IMAP resource folder" << endl;
00456 return false;
00457 }
00458
00459 bool rc = false;
00460
00461 KMMessage* msg = findMessageBySerNum( sernum, f );
00462 if( msg ) {
00463
00464 deleteMsg( msg );
00465 rc = true;
00466 } else {
00467 kdDebug(5006) << "Message not found, cannot remove serNum " << sernum << endl;
00468 }
00469 return rc;
00470 }
00471
00472
00473 int KMailICalIfaceImpl::incidencesKolabCount( const QString& mimetype,
00474 const QString& resource )
00475 {
00476 if( !mUseResourceIMAP )
00477 return 0;
00478
00479 KMFolder* f = findResourceFolder( resource );
00480 if( !f ) {
00481 kdError(5006) << "incidencesKolab(" << resource << ") : Not an IMAP resource folder" << endl;
00482 return 0;
00483 }
00484
00485 f->open("kolabcount");
00486 int n = f->count();
00487 f->close("kolabcount");
00488 kdDebug(5006) << "KMailICalIfaceImpl::incidencesKolabCount( " << mimetype << ", "
00489 << resource << " ) returned " << n << endl;
00490 return n;
00491 }
00492
00493 QMap<Q_UINT32, QString> KMailICalIfaceImpl::incidencesKolab( const QString& mimetype,
00494 const QString& resource,
00495 int startIndex,
00496 int nbMessages )
00497 {
00501
00502 QMap<Q_UINT32, QString> aMap;
00503 if( !mUseResourceIMAP )
00504 return aMap;
00505
00506 KMFolder* f = findResourceFolder( resource );
00507 if( !f ) {
00508 kdError(5006) << "incidencesKolab(" << resource << ") : Not an IMAP resource folder" << endl;
00509 return aMap;
00510 }
00511
00512 f->open("incidences");
00513
00514 int stopIndex = nbMessages == -1 ? f->count() :
00515 QMIN( f->count(), startIndex + nbMessages );
00516 kdDebug(5006) << "KMailICalIfaceImpl::incidencesKolab( " << mimetype << ", "
00517 << resource << " ) from " << startIndex << " to " << stopIndex << endl;
00518
00519 for(int i = startIndex; i < stopIndex; ++i) {
00520 #if 0
00521 bool unget = !f->isMessage(i);
00522 KMMessage* msg = f->getMsg( i );
00523 #else // faster
00524 KMMessage* msg = f->storage()->readTemporaryMsg(i);
00525 #endif
00526 if ( msg ) {
00527 const int iSlash = mimetype.find('/');
00528 const QCString sType = mimetype.left( iSlash ).latin1();
00529 const QCString sSubtype = mimetype.mid( iSlash+1 ).latin1();
00530 if ( sType.isEmpty() || sSubtype.isEmpty() ) {
00531 kdError(5006) << mimetype << " not an type/subtype combination" << endl;
00532 } else {
00533 DwBodyPart* dwPart = findBodyPartByMimeType( *msg, sType, sSubtype );
00534 if ( dwPart ) {
00535 KMMessagePart msgPart;
00536 KMMessage::bodyPart(dwPart, &msgPart);
00537 aMap.insert(msg->getMsgSerNum(), msgPart.bodyToUnicode( QTextCodec::codecForName( "utf8" ) ));
00538 } else {
00539
00540
00541
00542 const QCString type( msg->typeStr() );
00543 const QCString subtype( msg->subtypeStr() );
00544 if (type.lower() == sType && subtype.lower() == sSubtype ) {
00545 aMap.insert( msg->getMsgSerNum(), msg->bodyToUnicode() );
00546 }
00547
00548
00549 }
00550 }
00551 #if 0
00552 if( unget ) f->unGetMsg(i);
00553 #else
00554 delete msg;
00555 #endif
00556 }
00557 }
00558 f->close( "incidences" );
00559 return aMap;
00560 }
00561
00562
00563
00564
00565
00566 void KMailICalIfaceImpl::slotMessageRetrieved( KMMessage* msg )
00567 {
00568 if( !msg ) return;
00569
00570 KMFolder *parent = msg->parent();
00571 Q_ASSERT( parent );
00572 Q_UINT32 sernum = msg->getMsgSerNum();
00573
00574
00575 Accumulator *ac = mAccumulators.find( parent->location() );
00576 if( ac ) {
00577 QString s;
00578 if ( !vPartFoundAndDecoded( msg, s ) ) return;
00579 QString uid( "UID" );
00580 vPartMicroParser( s, uid );
00581 const Q_UINT32 sernum = msg->getMsgSerNum();
00582 mUIDToSerNum.insert( uid, sernum );
00583 ac->add( s );
00584 if( ac->isFull() ) {
00585
00586
00587
00588 mAccumulators.remove( ac->folder );
00589 }
00590 } else {
00591
00592
00593 slotIncidenceAdded( msg->parent(), msg->getMsgSerNum() );
00594 }
00595
00596 if ( mTheUnGetMes.contains( sernum ) ) {
00597 mTheUnGetMes.remove( sernum );
00598 int i = 0;
00599 KMFolder* folder = 0;
00600 KMMsgDict::instance()->getLocation( sernum, &folder, &i );
00601 folder->unGetMsg( i );
00602 }
00603 }
00604
00605
00606 QValueList<KMailICalIfaceImpl::SubResource> KMailICalIfaceImpl::subresourcesKolab( const QString& contentsType )
00607 {
00608 QValueList<SubResource> subResources;
00609
00610
00611 KMFolder* f = folderFromType( contentsType, QString::null );
00612 if ( f ) {
00613 subResources.append( SubResource( f->location(), f->prettyURL(), !f->isReadOnly() ) );
00614 kdDebug(5006) << "Adding(1) folder " << f->location() << " " <<
00615 ( f->isReadOnly() ? "readonly" : "" ) << endl;
00616 }
00617
00618
00619 const KMail::FolderContentsType t = folderContentsType( contentsType );
00620 QDictIterator<ExtraFolder> it( mExtraFolders );
00621 for ( ; it.current(); ++it ){
00622 f = it.current()->folder;
00623 if ( f && f->storage()->contentsType() == t ) {
00624 subResources.append( SubResource( f->location(), f->prettyURL(), !f->isReadOnly() ) );
00625 kdDebug(5006) << "Adding(2) folder " << f->location() << " " <<
00626 ( f->isReadOnly() ? "readonly" : "" ) << endl;
00627 }
00628 }
00629
00630 if ( subResources.isEmpty() )
00631 kdDebug(5006) << "subresourcesKolab: No folder found for " << contentsType << endl;
00632 return subResources;
00633 }
00634
00635 bool KMailICalIfaceImpl::triggerSync( const QString& contentsType )
00636 {
00637 kdDebug(5006) << k_funcinfo << endl;
00638 QValueList<KMailICalIfaceImpl::SubResource> folderList = subresourcesKolab( contentsType );
00639 for ( QValueList<KMailICalIfaceImpl::SubResource>::const_iterator it( folderList.begin() ),
00640 end( folderList.end() );
00641 it != end ; ++it ) {
00642 KMFolder * const f = findResourceFolder( (*it).location );
00643 if ( !f ) continue;
00644 if ( f->folderType() == KMFolderTypeImap || f->folderType() == KMFolderTypeCachedImap ) {
00645 if ( !kmkernel->askToGoOnline() ) {
00646 return false;
00647 }
00648 }
00649
00650 if ( f->folderType() == KMFolderTypeImap ) {
00651 KMFolderImap *imap = static_cast<KMFolderImap*>( f->storage() );
00652 imap->getAndCheckFolder();
00653 } else if ( f->folderType() == KMFolderTypeCachedImap ) {
00654 KMFolderCachedImap* cached = static_cast<KMFolderCachedImap*>( f->storage() );
00655 cached->account()->processNewMailSingleFolder( f );
00656 }
00657 }
00658 return true;
00659 }
00660
00661
00662 bool KMailICalIfaceImpl::isWritableFolder( const QString& type,
00663 const QString& resource )
00664 {
00665 KMFolder* f = folderFromType( type, resource );
00666 if ( !f )
00667
00668 return false;
00669
00670 return !f->isReadOnly();
00671 }
00672
00673
00674 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( const QString& resource )
00675 {
00676 StorageFormat format;
00677 KMFolder* f = findResourceFolder( resource );
00678 if ( f )
00679 format = storageFormat( f );
00680 else
00681 format = globalStorageFormat();
00682 return format;
00683 }
00684
00699 Q_UINT32 KMailICalIfaceImpl::update( const QString& resource,
00700 Q_UINT32 sernum,
00701 const QString& subject,
00702 const QString& plainTextBody,
00703 const QMap<QCString, QString>& customHeaders,
00704 const QStringList& attachmentURLs,
00705 const QStringList& attachmentMimetypes,
00706 const QStringList& attachmentNames,
00707 const QStringList& deletedAttachments )
00708 {
00709 Q_UINT32 rc = 0;
00710
00711 if( !mUseResourceIMAP )
00712 return rc;
00713
00714 Q_ASSERT( !resource.isEmpty() );
00715
00716 kdDebug(5006) << "KMailICalIfaceImpl::update( " << resource << ", " << sernum << " )\n";
00717 kdDebug(5006) << attachmentURLs << "\n";
00718 kdDebug(5006) << attachmentMimetypes << "\n";
00719 kdDebug(5006) << attachmentNames << "\n";
00720 kdDebug(5006) << "deleted attachments:" << deletedAttachments << "\n";
00721
00722
00723 KMFolder* f = findResourceFolder( resource );
00724 if( !f ) {
00725 kdError(5006) << "update(" << resource << ") : Not an IMAP resource folder" << endl;
00726 return rc;
00727 }
00728
00729 f->open("ifaceupdate");
00730
00731 KMMessage* msg = 0;
00732 if ( sernum != 0 ) {
00733 msg = findMessageBySerNum( sernum, f );
00734 if ( !msg ) return 0;
00735
00736 KMMessage* newMsg = new KMMessage( *msg );
00737 newMsg->setSubject( subject );
00738 QMap<QCString, QString>::ConstIterator ith = customHeaders.begin();
00739 const QMap<QCString, QString>::ConstIterator ithEnd = customHeaders.begin();
00740 for ( ; ith != ithEnd ; ++ith )
00741 newMsg->setHeaderField( ith.key(), ith.data() );
00742 newMsg->setParent( 0 );
00743
00744
00745
00746 for( QStringList::ConstIterator it = deletedAttachments.begin();
00747 it != deletedAttachments.end();
00748 ++it ){
00749 if( !deleteAttachment( *newMsg, *it ) ){
00750
00751 }
00752 }
00753
00754 const KMail::FolderContentsType t = f->storage()->contentsType();
00755 const QCString type = msg->typeStr();
00756 const QCString subtype = msg->subtypeStr();
00757 const bool messageWasIcalVcardFormat = ( type.lower() == "text" &&
00758 ( subtype.lower() == "calendar" || subtype.lower() == "x-vcard" ) );
00759
00760 if ( storageFormat( f ) == StorageIcalVcard ) {
00761
00762 if ( !messageWasIcalVcardFormat ) {
00763 setIcalVcardContentTypeHeader( newMsg, t );
00764 }
00765 newMsg->setBodyEncoded( plainTextBody.utf8() );
00766 } else if ( storageFormat( f ) == StorageXML ) {
00767 if ( messageWasIcalVcardFormat ) {
00768
00769
00770 setXMLContentTypeHeader( newMsg, plainTextBody );
00771 }
00772
00773
00774 QStringList::ConstIterator iturl = attachmentURLs.begin();
00775 QStringList::ConstIterator itmime = attachmentMimetypes.begin();
00776 QStringList::ConstIterator itname = attachmentNames.begin();
00777 for( ;
00778 iturl != attachmentURLs.end()
00779 && itmime != attachmentMimetypes.end()
00780 && itname != attachmentNames.end();
00781 ++iturl, ++itname, ++itmime ){
00782 bool bymimetype = (*itname).startsWith( "application/x-vnd.kolab." );
00783 if( !updateAttachment( *newMsg, *iturl, *itname, *itmime, bymimetype ) ){
00784 kdDebug(5006) << "Attachment error, can not update attachment " << *iturl << endl;
00785 break;
00786 }
00787 }
00788 }
00789
00790
00791
00792
00793 newMsg->cleanupHeader();
00794
00795
00796
00797 deleteMsg( msg );
00798 if ( f->addMsg( newMsg ) == 0 ) {
00799
00800 rc = newMsg->getMsgSerNum();
00801 kdDebug(5006) << "forget about " << sernum << ", it's " << rc << " now" << endl;
00802 }
00803 addFolderChange( f, Contents );
00804 } else {
00805
00806 rc = addIncidenceKolab( *f, subject, plainTextBody, customHeaders,
00807 attachmentURLs,
00808 attachmentNames,
00809 attachmentMimetypes );
00810 }
00811
00812 f->close("ifaceupdate");
00813 return rc;
00814 }
00815
00816 KURL KMailICalIfaceImpl::getAttachment( const QString& resource,
00817 Q_UINT32 sernum,
00818 const QString& filename )
00819 {
00820
00821
00822
00823 if( !mUseResourceIMAP )
00824 return KURL();
00825
00826 kdDebug(5006) << "KMailICalIfaceImpl::getAttachment( "
00827 << resource << ", " << sernum << ", " << filename << " )\n";
00828
00829
00830 KMFolder* f = findResourceFolder( resource );
00831 if( !f ) {
00832 kdError(5006) << "getAttachment(" << resource << ") : Not an IMAP resource folder" << endl;
00833 return KURL();
00834 }
00835 if ( storageFormat( f ) != StorageXML ) {
00836 kdError(5006) << "getAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
00837 return KURL();
00838 }
00839
00840 KURL url;
00841
00842 bool bOK = false;
00843 bool quiet = mResourceQuiet;
00844 mResourceQuiet = true;
00845
00846 KMMessage* msg = findMessageBySerNum( sernum, f );
00847 if( msg ) {
00848
00849
00850 DwBodyPart* part = findBodyPart( *msg, filename );
00851 if ( part ) {
00852
00853 KMMessagePart aPart;
00854 msg->bodyPart( part, &aPart );
00855 QByteArray rawData( aPart.bodyDecodedBinary() );
00856
00857 KTempFile file;
00858 file.file()->writeBlock( rawData.data(), rawData.size() );
00859
00860 url.setPath( file.name() );
00861
00862 bOK = true;
00863 }
00864
00865 if( !bOK ){
00866 kdDebug(5006) << "Attachment " << filename << " not found." << endl;
00867 }
00868 }else{
00869 kdDebug(5006) << "Message not found." << endl;
00870 }
00871
00872 mResourceQuiet = quiet;
00873 return url;
00874 }
00875
00876
00877
00878
00879
00880
00881
00882 void KMailICalIfaceImpl::slotFolderRemoved( KMFolder* folder )
00883 {
00884
00885
00886 folderContentsTypeChanged( folder, KMail::ContentsTypeMail );
00887 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
00888 configGroup.deleteEntry( folder->idString() + "-storageFormat" );
00889 configGroup.deleteEntry( folder->idString() + "-changes" );
00890 }
00891
00892
00893 void KMailICalIfaceImpl::slotIncidenceAdded( KMFolder* folder,
00894 Q_UINT32 sernum )
00895 {
00896 if( mResourceQuiet || !mUseResourceIMAP )
00897 return;
00898
00899
00900 QString type = folderContentsType( folder->storage()->contentsType() );
00901 if( type.isEmpty() ) {
00902 kdError(5006) << "Not an IMAP resource folder" << endl;
00903 return;
00904 }
00905
00906 int i = 0;
00907 KMFolder* aFolder = 0;
00908 KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
00909 assert( folder == aFolder );
00910
00911 bool unget = !folder->isMessage( i );
00912 QString s;
00913 QString uid( "UID" );
00914 KMMessage *msg = folder->getMsg( i );
00915 if( !msg ) return;
00916 if( msg->isComplete() ) {
00917
00918 bool ok = false;
00919 StorageFormat format = storageFormat( folder );
00920 switch( format ) {
00921 case StorageIcalVcard:
00922
00923 ok = vPartFoundAndDecoded( msg, s );
00924 if ( ok )
00925 vPartMicroParser( s, uid );
00926 break;
00927 case StorageXML:
00928
00929 if ( kolabXMLFoundAndDecoded( *msg,
00930 folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
00931 uid = msg->subject();
00932 ok = true;
00933 }
00934 break;
00935 }
00936 if ( !ok ) {
00937 if ( unget )
00938 folder->unGetMsg( i );
00939 return;
00940 }
00941 const Q_UINT32 sernum = msg->getMsgSerNum();
00942 mUIDToSerNum.insert( uid, sernum );
00943
00944
00945 if ( mInTransit.contains( uid ) ) {
00946 mInTransit.remove( uid );
00947 }
00948 incidenceAdded( type, folder->location(), sernum, format, s );
00949 } else {
00950
00951
00952 if ( unget ) mTheUnGetMes.insert( msg->getMsgSerNum(), true );
00953 FolderJob *job = msg->parent()->createJob( msg );
00954 connect( job, SIGNAL( messageRetrieved( KMMessage* ) ),
00955 this, SLOT( slotMessageRetrieved( KMMessage* ) ) );
00956 job->start();
00957 return;
00958 }
00959 if( unget ) folder->unGetMsg(i);
00960 }
00961
00962
00963 void KMailICalIfaceImpl::slotIncidenceDeleted( KMFolder* folder,
00964 Q_UINT32 sernum )
00965 {
00966 if( mResourceQuiet || !mUseResourceIMAP )
00967 return;
00968
00969 QString type = folderContentsType( folder->storage()->contentsType() );
00970
00971 if( !type.isEmpty() ) {
00972
00973 int i = 0;
00974 KMFolder* aFolder = 0;
00975 KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
00976 assert( folder == aFolder );
00977
00978
00979 bool unget = !folder->isMessage( i );
00980 QString s;
00981 bool ok = false;
00982 KMMessage* msg = folder->getMsg( i );
00983 QString uid( "UID" );
00984 switch( storageFormat( folder ) ) {
00985 case StorageIcalVcard:
00986 if( vPartFoundAndDecoded( msg, s ) ) {
00987 vPartMicroParser( s, uid );
00988 ok = true;
00989 }
00990 break;
00991 case StorageXML:
00992 if ( kolabXMLFoundAndDecoded( *msg, folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
00993 uid = msg->subject();
00994 ok = true;
00995 }
00996 break;
00997 }
00998 if ( ok ) {
00999 kdDebug(5006) << "Emitting DCOP signal incidenceDeleted( "
01000 << type << ", " << folder->location() << ", " << uid
01001 << " )" << endl;
01002 incidenceDeleted( type, folder->location(), uid );
01003 }
01004 if( unget ) folder->unGetMsg(i);
01005 } else
01006 kdError(5006) << "Not a groupware folder" << endl;
01007 }
01008
01009
01010 void KMailICalIfaceImpl::slotRefresh( const QString& type )
01011 {
01012 if( mUseResourceIMAP ) {
01013 signalRefresh( type, QString::null );
01014 kdDebug(5006) << "Emitting DCOP signal signalRefresh( " << type << " )" << endl;
01015 }
01016 }
01017
01018
01019 void KMailICalIfaceImpl::slotRefreshFolder( KMFolder* folder)
01020 {
01021
01022
01023
01024 if( mUseResourceIMAP && folder ) {
01025 if( folder == mCalendar || folder == mContacts
01026 || folder == mNotes || folder == mTasks
01027 || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01028
01029 KMail::FolderContentsType ct = folder->storage()->contentsType();
01030 slotRefresh( s_folderContentsType[ct].contentsTypeStr );
01031 }
01032 }
01033 }
01034
01035
01036
01037
01038
01039 KMFolder* KMailICalIfaceImpl::folderFromType( const QString& type,
01040 const QString& folder )
01041 {
01042 if( mUseResourceIMAP ) {
01043 KMFolder* f = 0;
01044 if ( !folder.isEmpty() ) {
01045 f = extraFolder( type, folder );
01046 if ( f )
01047 return f;
01048 }
01049
01050 if( type == "Calendar" ) f = mCalendar;
01051 else if( type == "Contact" ) f = mContacts;
01052 else if( type == "Note" ) f = mNotes;
01053 else if( type == "Task" || type == "Todo" ) f = mTasks;
01054 else if( type == "Journal" ) f = mJournals;
01055
01056 if ( f && ( folder.isEmpty() || folder == f->location() ) )
01057 return f;
01058
01059 kdError(5006) << "No folder ( " << type << ", " << folder << " )\n";
01060 }
01061
01062 return 0;
01063 }
01064
01065
01066
01067
01068 bool KMailICalIfaceImpl::isResourceFolder( KMFolder* folder ) const
01069 {
01070 return mUseResourceIMAP && folder &&
01071 ( isStandardResourceFolder( folder ) || mExtraFolders.find( folder->location() )!=0 );
01072 }
01073
01074 bool KMailICalIfaceImpl::isStandardResourceFolder( KMFolder* folder ) const
01075 {
01076 return ( folder == mCalendar || folder == mTasks || folder == mJournals ||
01077 folder == mNotes || folder == mContacts );
01078 }
01079
01080 bool KMailICalIfaceImpl::hideResourceFolder( KMFolder* folder ) const
01081 {
01082 return mHideFolders && isResourceFolder( folder );
01083 }
01084
01085 bool KMailICalIfaceImpl::hideResourceAccountRoot( KMFolder* folder ) const
01086 {
01087 KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
01088 bool hide = dimapFolder && mHideFolders
01089 && (int)dimapFolder->account()->id() == GlobalSettings::self()->theIMAPResourceAccount()
01090 && GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount();
01091 return hide;
01092
01093 }
01094
01095 KFolderTreeItem::Type KMailICalIfaceImpl::folderType( KMFolder* folder ) const
01096 {
01097 if( mUseResourceIMAP && folder ) {
01098 if( folder == mCalendar || folder == mContacts
01099 || folder == mNotes || folder == mTasks
01100 || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01101 KMail::FolderContentsType ct = folder->storage()->contentsType();
01102 return s_folderContentsType[ct].treeItemType;
01103 }
01104 }
01105
01106 return KFolderTreeItem::Other;
01107 }
01108
01109
01110
01111 static QMap<KFolderTreeItem::Type,QString> folderNames[4];
01112 QString KMailICalIfaceImpl::folderName( KFolderTreeItem::Type type, int language ) const
01113 {
01114
01115 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
01116 language = 0;
01117
01118 static bool folderNamesSet = false;
01119 if( !folderNamesSet ) {
01120 folderNamesSet = true;
01121
01122
01123
01124
01125 folderNames[0][KFolderTreeItem::Calendar] = QString::fromLatin1("Calendar");
01126 folderNames[0][KFolderTreeItem::Tasks] = QString::fromLatin1("Tasks");
01127 folderNames[0][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01128 folderNames[0][KFolderTreeItem::Contacts] = QString::fromLatin1("Contacts");
01129 folderNames[0][KFolderTreeItem::Notes] = QString::fromLatin1("Notes");
01130
01131
01132 folderNames[1][KFolderTreeItem::Calendar] = QString::fromLatin1("Kalender");
01133 folderNames[1][KFolderTreeItem::Tasks] = QString::fromLatin1("Aufgaben");
01134 folderNames[1][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01135 folderNames[1][KFolderTreeItem::Contacts] = QString::fromLatin1("Kontakte");
01136 folderNames[1][KFolderTreeItem::Notes] = QString::fromLatin1("Notizen");
01137
01138
01139 folderNames[2][KFolderTreeItem::Calendar] = QString::fromLatin1("Calendrier");
01140 folderNames[2][KFolderTreeItem::Tasks] = QString::fromLatin1("Tâches");
01141 folderNames[2][KFolderTreeItem::Journals] = QString::fromLatin1("Journal");
01142 folderNames[2][KFolderTreeItem::Contacts] = QString::fromLatin1("Contacts");
01143 folderNames[2][KFolderTreeItem::Notes] = QString::fromLatin1("Notes");
01144
01145
01146 folderNames[3][KFolderTreeItem::Calendar] = QString::fromLatin1("Agenda");
01147 folderNames[3][KFolderTreeItem::Tasks] = QString::fromLatin1("Taken");
01148 folderNames[3][KFolderTreeItem::Journals] = QString::fromLatin1("Logboek");
01149 folderNames[3][KFolderTreeItem::Contacts] = QString::fromLatin1("Contactpersonen");
01150 folderNames[3][KFolderTreeItem::Notes] = QString::fromLatin1("Notities");
01151 }
01152
01153 if( language < 0 || language > 3 ) {
01154 return folderNames[mFolderLanguage][type];
01155 }
01156 else {
01157 return folderNames[language][type];
01158 }
01159 }
01160
01161
01162
01163 KMMessage *KMailICalIfaceImpl::findMessageByUID( const QString& uid, KMFolder* folder )
01164 {
01165 if( !folder || !mUIDToSerNum.contains( uid ) ) return 0;
01166 int i;
01167 KMFolder *aFolder;
01168 KMMsgDict::instance()->getLocation( mUIDToSerNum[uid], &aFolder, &i );
01169 Q_ASSERT( aFolder == folder );
01170 return folder->getMsg( i );
01171 }
01172
01173
01174 KMMessage *KMailICalIfaceImpl::findMessageBySerNum( Q_UINT32 serNum, KMFolder* folder )
01175 {
01176 if( !folder ) return 0;
01177
01178 KMMessage *message = 0;
01179 KMFolder* aFolder = 0;
01180 int index;
01181 KMMsgDict::instance()->getLocation( serNum, &aFolder, &index );
01182 if( aFolder && aFolder != folder ) {
01183 kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) found it in folder " << aFolder->location() << ", expected " << folder->location() << endl;
01184 } else {
01185 if( aFolder )
01186 message = aFolder->getMsg( index );
01187 if (!message)
01188 kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) invalid serial number\n" << endl;
01189 }
01190 return message;
01191 }
01192
01193 void KMailICalIfaceImpl::deleteMsg( KMMessage *msg )
01194 {
01195 if( !msg ) return;
01196
01197
01198 KMFolder *srcFolder = msg->parent();
01199 int idx = srcFolder->find(msg);
01200 assert(idx != -1);
01201 srcFolder->removeMsg(idx);
01202 delete msg;
01203 addFolderChange( srcFolder, Contents );
01204 }
01205
01206 void KMailICalIfaceImpl::folderContentsTypeChanged( KMFolder* folder,
01207 KMail::FolderContentsType contentsType )
01208 {
01209 if ( !mUseResourceIMAP )
01210 return;
01211
01212
01213
01214
01215 if ( isStandardResourceFolder( folder ) )
01216 return;
01217
01218
01219 const QString location = folder->location();
01220 ExtraFolder* ef = mExtraFolders.find( location );
01221 if ( ef && ef->folder ) {
01222
01223 subresourceDeleted(folderContentsType( folder->storage()->contentsType() ), location );
01224
01225 if ( contentsType == 0 ) {
01226
01227 mExtraFolders.remove( location );
01228 folder->disconnect( this );
01229 return;
01230 }
01231
01232 } else {
01233 if ( ef && !ef->folder )
01234 mExtraFolders.remove( location );
01235 if ( contentsType == 0 )
01236 return;
01237
01238
01239
01240 ef = new ExtraFolder( folder );
01241 mExtraFolders.insert( location, ef );
01242
01243 FolderInfo info = readFolderInfo( folder );
01244 mFolderInfoMap.insert( folder, info );
01245
01246
01247
01248
01249
01250
01251 if ( folder->folderType() == KMFolderTypeCachedImap ) {
01252 QString annotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
01253 kdDebug(5006) << "folderContentsTypeChanged: " << folder->name() << " has annotation " << annotation << endl;
01254 if ( annotation == QString( s_folderContentsType[contentsType].annotation ) + ".default" )
01255 folder->setLabel( localizedDefaultFolderName( contentsType ) );
01256 }
01257
01258 connectFolder( folder );
01259 }
01260
01261 subresourceAdded( folderContentsType( contentsType ), location, folder->prettyURL() );
01262 }
01263
01264 KMFolder* KMailICalIfaceImpl::extraFolder( const QString& type,
01265 const QString& folder )
01266 {
01267
01268
01269 int t = folderContentsType( type );
01270 if ( t < 1 || t > 5 )
01271 return 0;
01272
01273 ExtraFolder* ef = mExtraFolders.find( folder );
01274 if ( ef && ef->folder && ef->folder->storage()->contentsType() == t )
01275 return ef->folder;
01276
01277 return 0;
01278 }
01279
01280 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( KMFolder* folder ) const
01281 {
01282 FolderInfoMap::ConstIterator it = mFolderInfoMap.find( folder );
01283 if ( it != mFolderInfoMap.end() )
01284 return (*it).mStorageFormat;
01285 return globalStorageFormat();
01286 }
01287
01288 void KMailICalIfaceImpl::setStorageFormat( KMFolder* folder, StorageFormat format )
01289 {
01290 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01291 if ( it != mFolderInfoMap.end() ) {
01292 (*it).mStorageFormat = format;
01293 } else {
01294 FolderInfo info( format, NoChange );
01295 mFolderInfoMap.insert( folder, info );
01296 }
01297 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01298 configGroup.writeEntry( folder->idString() + "-storageFormat",
01299 format == StorageXML ? "xml" : "icalvcard" );
01300 }
01301
01302 void KMailICalIfaceImpl::addFolderChange( KMFolder* folder, FolderChanges changes )
01303 {
01304 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01305 if ( it != mFolderInfoMap.end() ) {
01306 (*it).mChanges = static_cast<FolderChanges>( (*it).mChanges | changes );
01307 } else {
01308 kdDebug(5006) << "addFolderChange: nothing known about folder " << folder->location() << endl;
01309 }
01310 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01311 configGroup.writeEntry( folder->idString() + "-changes", (*it).mChanges );
01312 }
01313
01314 KMailICalIfaceImpl::FolderInfo KMailICalIfaceImpl::readFolderInfo( const KMFolder * const folder ) const
01315 {
01316 KConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
01317 QString str = configGroup.readEntry( folder->idString() + "-storageFormat", "unset" );
01318 FolderInfo info;
01319 if ( str == "unset" ) {
01320 info.mStorageFormat = globalStorageFormat();
01321 configGroup.writeEntry( folder->idString() + "-storageFormat",
01322 info.mStorageFormat == StorageXML ? "xml" : "icalvcard" );
01323 } else {
01324 info.mStorageFormat = ( str == "xml" ) ? StorageXML : StorageIcalVcard;
01325 }
01326 info.mChanges = (FolderChanges) configGroup.readNumEntry( folder->idString() + "-changes" );
01327 return info;
01328 }
01329
01330
01331 void KMailICalIfaceImpl::folderSynced( KMFolder* folder, const KURL& folderURL )
01332 {
01333 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
01334 if ( it != mFolderInfoMap.end() && (*it).mChanges ) {
01335 handleFolderSynced( folder, folderURL, (*it).mChanges );
01336 (*it).mChanges = NoChange;
01337 }
01338 }
01339
01340 void KMailICalIfaceImpl::handleFolderSynced( KMFolder* folder,
01341 const KURL& folderURL,
01342 int _changes )
01343 {
01344
01345
01346
01347
01348 if ( ( _changes & KMailICalIface::Contents ) ||
01349 ( _changes & KMailICalIface::ACL ) ) {
01350 if ( storageFormat( folder ) == StorageXML && folder->storage()->contentsType() == KMail::ContentsTypeCalendar )
01351 triggerKolabFreeBusy( folderURL );
01352 }
01353 }
01354
01355 void KMailICalIfaceImpl::folderDeletedOnServer( const KURL& folderURL )
01356 {
01357 triggerKolabFreeBusy( folderURL );
01358 }
01359
01360 void KMailICalIfaceImpl::triggerKolabFreeBusy( const KURL& folderURL )
01361 {
01362
01363
01364
01365 KURL httpURL( folderURL );
01366
01367 httpURL.setProtocol( "https" );
01368 httpURL.setPort( 0 );
01369
01370
01371 QString path = folderURL.path( -1 );
01372 Q_ASSERT( path.startsWith( "/" ) );
01373 int secondSlash = path.find( '/', 1 );
01374 if ( secondSlash == -1 ) {
01375 kdWarning() << "KCal::ResourceKolab::fromKMailFolderSynced path is too short: " << path << endl;
01376 return;
01377 }
01378 if ( path.startsWith( "/INBOX/", false ) ) {
01379
01380 path = path.mid( secondSlash );
01381 path.prepend( folderURL.user() );
01382 } else {
01383
01384
01385 path = path.mid( secondSlash );
01386 }
01387
01388 httpURL.setPath( "/freebusy/trigger/" + path + ".pfb" );
01389 httpURL.setQuery( QString::null );
01390
01391 httpURL = KURL( httpURL.url(0,106), 106 );
01392 kdDebug() << "Triggering PFB update for " << folderURL << " : getting " << httpURL << endl;
01393
01394
01395 KIO::get( httpURL, false, false );
01396 }
01397
01398 void KMailICalIfaceImpl::slotFolderPropertiesChanged( KMFolder* folder )
01399 {
01400 if ( isResourceFolder( folder ) ) {
01401 const QString location = folder->location();
01402 const QString contentsTypeStr = folderContentsType( folder->storage()->contentsType() );
01403 subresourceDeleted( contentsTypeStr, location );
01404
01405 subresourceAdded( contentsTypeStr, location, folder->prettyURL()
01406 );
01407
01408 }
01409 }
01410
01411
01412 void KMailICalIfaceImpl::slotFolderRenamed()
01413 {
01414 const KMFolder* folder = static_cast<const KMFolder *>( sender() );
01415 slotFolderPropertiesChanged( const_cast<KMFolder*>( folder ) );
01416 }
01417
01418 void KMailICalIfaceImpl::slotFolderLocationChanged( const QString &oldLocation,
01419 const QString &newLocation )
01420 {
01421 KMFolder *folder = findResourceFolder( oldLocation );
01422 ExtraFolder* ef = mExtraFolders.find( oldLocation );
01423 if ( ef ) {
01424
01425 mExtraFolders.setAutoDelete( false );
01426 mExtraFolders.remove( oldLocation );
01427 mExtraFolders.setAutoDelete( true );
01428 mExtraFolders.insert( newLocation, ef );
01429 }
01430 if ( folder )
01431 subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), oldLocation );
01432
01433 }
01434
01435 KMFolder* KMailICalIfaceImpl::findResourceFolder( const QString& resource )
01436 {
01437
01438 if( mCalendar && mCalendar->location() == resource )
01439 return mCalendar;
01440 if ( mContacts && mContacts->location() == resource )
01441 return mContacts;
01442 if ( mNotes && mNotes->location() == resource )
01443 return mNotes;
01444 if ( mTasks && mTasks->location() == resource )
01445 return mTasks;
01446 if ( mJournals && mJournals->location() == resource )
01447 return mJournals;
01448
01449
01450 ExtraFolder* ef = mExtraFolders.find( resource );
01451 if ( ef )
01452 return ef->folder;
01453
01454
01455 return 0;
01456 }
01457
01458
01459
01460
01461
01462 void KMailICalIfaceImpl::readConfig()
01463 {
01464 bool enabled = GlobalSettings::self()->theIMAPResourceEnabled();
01465
01466 if( !enabled ) {
01467 if( mUseResourceIMAP == true ) {
01468
01469 mUseResourceIMAP = false;
01470 cleanup();
01471 reloadFolderTree();
01472 }
01473 return;
01474 }
01475 mUseResourceIMAP = enabled;
01476
01477
01478 const bool hideFolders = GlobalSettings::self()->hideGroupwareFolders();
01479 QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01480
01481
01482 KMFolderDir* folderParentDir;
01483 KMFolderType folderType;
01484 KMFolder* folderParent = kmkernel->findFolderById( parentName );
01485 if( folderParent == 0 ) {
01486
01487
01488 kdDebug(5006) << "Groupware folder " << parentName << " not found. Groupware functionality disabled" << endl;
01489
01490 KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01491 Q_ASSERT( account );
01492 if ( account ) {
01493
01494 disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01495 this, SLOT( slotCheckDone() ) );
01496 connect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01497 this, SLOT( slotCheckDone() ) );
01498 }
01499 mUseResourceIMAP = false;
01500
01501 mCalendar = 0;
01502 mTasks = 0;
01503 mJournals = 0;
01504 mContacts = 0;
01505 mNotes = 0;
01506 return;
01507 } else {
01508 folderParentDir = folderParent->createChildFolder();
01509 folderType = folderParent->folderType();
01510 }
01511
01512
01513
01514 bool noneFound = true;
01515 bool mustFix = false;
01516 QValueVector<StandardFolderSearchResult> results( KMail::ContentsTypeLast + 1 );
01517 for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01518 if ( i != KMail::ContentsTypeMail ) {
01519 results[i] = findStandardResourceFolder( folderParentDir, static_cast<KMail::FolderContentsType>(i) );
01520 if ( results[i].found == StandardFolderSearchResult::FoundAndStandard )
01521 noneFound = false;
01522 else if ( results[i].found == StandardFolderSearchResult::FoundByType ||
01523 results[i].found == StandardFolderSearchResult::FoundByName ) {
01524 mustFix = true;
01525 noneFound = false;
01526 } else
01527 mustFix = true;
01528 }
01529 }
01530
01531
01532 if( mUseResourceIMAP && !noneFound && !mustFix && mFolderParentDir == folderParentDir
01533 && mFolderType == folderType ) {
01534
01535 if ( hideFolders != mHideFolders ) {
01536
01537 mHideFolders = hideFolders;
01538 reloadFolderTree();
01539 }
01540 return;
01541 }
01542
01543 if( noneFound || mustFix ) {
01544 QString msg;
01545 QString parentFolderName = folderParent != 0 ? folderParent->name() : folderParentDir->name();
01546 if ( noneFound ) {
01547
01548 msg = i18n("KMail will now create the required groupware folders"
01549 " as subfolders of %1; if you do not want this, cancel"
01550 " and the IMAP resource will be disabled").arg(parentFolderName);
01551 } else {
01552
01553 QString operations = "<ul>";
01554 for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
01555 if ( i != KMail::ContentsTypeMail ) {
01556 QString typeName = localizedDefaultFolderName( static_cast<KMail::FolderContentsType>( i ) );
01557 if ( results[i].found == StandardFolderSearchResult::NotFound )
01558 operations += "<li>" + i18n( "%1: no folder found. It will be created." ).arg( typeName ) + "</li>";
01559 else if ( results[i].found == StandardFolderSearchResult::FoundByType || results[i].found == StandardFolderSearchResult::FoundByName )
01560 operations += "<li>" + i18n( "%1: found folder %2. It will be set as the main groupware folder." ).
01561 arg( typeName ).arg( results[i].folder->label() ) + "</li>";
01562 }
01563 }
01564 operations += "</ul>";
01565
01566 msg = i18n("<qt>KMail found the following groupware folders in %1 and needs to perform the following operations: %2"
01567 "<br>If you do not want this, cancel"
01568 " and the IMAP resource will be disabled").arg(parentFolderName, operations);
01569
01570 }
01571
01572 if( KMessageBox::questionYesNo( 0, msg,
01573 i18n("Standard Groupware Folders"), KStdGuiItem::cont(), KStdGuiItem::cancel() ) == KMessageBox::No ) {
01574
01575 GlobalSettings::self()->setTheIMAPResourceEnabled( false );
01576 mUseResourceIMAP = false;
01577 mFolderParentDir = 0;
01578 mFolderParent = 0;
01579 reloadFolderTree();
01580 return;
01581 }
01582 }
01583
01584
01585 mUseResourceIMAP = true;
01586 mFolderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
01587 if( mFolderLanguage > 3 ) mFolderLanguage = 0;
01588 mFolderParentDir = folderParentDir;
01589 mFolderParent = folderParent;
01590 mFolderType = folderType;
01591 mHideFolders = hideFolders;
01592
01593
01594 cleanup();
01595
01596
01597 mCalendar = initFolder( KMail::ContentsTypeCalendar );
01598 mTasks = initFolder( KMail::ContentsTypeTask );
01599 mJournals = initFolder( KMail::ContentsTypeJournal );
01600 mContacts = initFolder( KMail::ContentsTypeContact );
01601 mNotes = initFolder( KMail::ContentsTypeNote );
01602
01603
01604 if ( mCalendar->folderType() == KMFolderTypeCachedImap )
01605 static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
01606 if ( mTasks->folderType() == KMFolderTypeCachedImap )
01607 static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
01608 if ( mJournals->folderType() == KMFolderTypeCachedImap )
01609 static_cast<KMFolderCachedImap *>( mJournals->storage() )->updateAnnotationFolderType();
01610 if ( mContacts->folderType() == KMFolderTypeCachedImap )
01611 static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
01612 if ( mNotes->folderType() == KMFolderTypeCachedImap )
01613 static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
01614
01615
01616
01617
01618 kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
01619 kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
01620 kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
01621
01622
01623 QStringList folderNames;
01624 QValueList<QGuardedPtr<KMFolder> > folderList;
01625 kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
01626 for(QValueList<QGuardedPtr<KMFolder> >::iterator it = folderList.begin();
01627 it != folderList.end(); ++it)
01628 {
01629 FolderStorage* storage = (*it)->storage();
01630 if ( storage->contentsType() != 0 ) {
01631 folderContentsTypeChanged( *it, storage->contentsType() );
01632 }
01633 }
01634
01635
01636
01637 mExtraFolders.remove( mCalendar->location() );
01638 mExtraFolders.remove( mTasks->location() );
01639 mExtraFolders.remove( mJournals->location() );
01640 mExtraFolders.remove( mContacts->location() );
01641 mExtraFolders.remove( mNotes->location() );
01642
01643
01644
01645 subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label() );
01646 subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label() );
01647 subresourceAdded( folderContentsType( KMail::ContentsTypeJournal ), mJournals->location(), mJournals->label() );
01648 subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label() );
01649 subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label() );
01650
01651 reloadFolderTree();
01652 }
01653
01654 void KMailICalIfaceImpl::slotCheckDone()
01655 {
01656 QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01657 KMFolder* folderParent = kmkernel->findFolderById( parentName );
01658
01659 if ( folderParent )
01660 {
01661 KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01662 if ( account )
01663 disconnect( account, SIGNAL( finishedCheck( bool, CheckStatus ) ),
01664 this, SLOT( slotCheckDone() ) );
01665 readConfig();
01666 }
01667 }
01668
01669 KMFolder* KMailICalIfaceImpl::initFolder( KMail::FolderContentsType contentsType )
01670 {
01671
01672 KMFolderType type = mFolderType;
01673 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
01674
01675 KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
01676
01677
01678
01679 StandardFolderSearchResult result = findStandardResourceFolder( mFolderParentDir, contentsType );
01680 KMFolder* folder = result.folder;
01681
01682 if ( !folder ) {
01683
01684 folder =
01685 mFolderParentDir->createFolder( localizedDefaultFolderName( contentsType ), false, type );
01686 if( mFolderType == KMFolderTypeImap ) {
01687 KMFolderImap* parentFolder = static_cast<KMFolderImap*>( mFolderParent->storage() );
01688 parentFolder->createFolder( localizedDefaultFolderName( contentsType ) );
01689 static_cast<KMFolderImap*>( folder->storage() )->setAccount( parentFolder->account() );
01690 }
01691
01692 setStorageFormat( folder, globalStorageFormat() );
01693 } else {
01694 FolderInfo info = readFolderInfo( folder );
01695 mFolderInfoMap.insert( folder, info );
01696
01697 }
01698
01699 if( folder->canAccess() != 0 ) {
01700 KMessageBox::sorry(0, i18n("You do not have read/write permission to your %1 folder.")
01701 .arg( folderName( itemType ) ) );
01702 return 0;
01703 }
01704 folder->storage()->setContentsType( contentsType );
01705 folder->setSystemFolder( true );
01706 folder->storage()->writeConfig();
01707 folder->open("ifacefolder");
01708 connectFolder( folder );
01709 return folder;
01710 }
01711
01712 void KMailICalIfaceImpl::connectFolder( KMFolder* folder )
01713 {
01714
01715 disconnect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
01716 this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
01717 disconnect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
01718 this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
01719 disconnect( folder, SIGNAL( expunged( KMFolder* ) ),
01720 this, SLOT( slotRefreshFolder( KMFolder* ) ) );
01721 disconnect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
01722 this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
01723 disconnect( folder, SIGNAL( nameChanged() ),
01724 this, SLOT( slotFolderRenamed() ) );
01725 disconnect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
01726 this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
01727
01728
01729 connect( folder, SIGNAL( msgAdded( KMFolder*, Q_UINT32 ) ),
01730 this, SLOT( slotIncidenceAdded( KMFolder*, Q_UINT32 ) ) );
01731 connect( folder, SIGNAL( msgRemoved( KMFolder*, Q_UINT32 ) ),
01732 this, SLOT( slotIncidenceDeleted( KMFolder*, Q_UINT32 ) ) );
01733 connect( folder, SIGNAL( expunged( KMFolder* ) ),
01734 this, SLOT( slotRefreshFolder( KMFolder* ) ) );
01735 connect( folder->storage(), SIGNAL( readOnlyChanged( KMFolder* ) ),
01736 this, SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
01737 connect( folder, SIGNAL( nameChanged() ),
01738 this, SLOT( slotFolderRenamed() ) );
01739 connect( folder->storage(), SIGNAL( locationChanged( const QString&, const QString&) ),
01740 this, SLOT( slotFolderLocationChanged( const QString&, const QString&) ) );
01741
01742 }
01743
01744 static void cleanupFolder( KMFolder* folder, KMailICalIfaceImpl* _this )
01745 {
01746 if( folder ) {
01747 folder->setSystemFolder( false );
01748 folder->disconnect( _this );
01749 folder->close("ifacefolder");
01750 }
01751 }
01752
01753 void KMailICalIfaceImpl::cleanup()
01754 {
01755 cleanupFolder( mContacts, this );
01756 cleanupFolder( mCalendar, this );
01757 cleanupFolder( mNotes, this );
01758 cleanupFolder( mTasks, this );
01759 cleanupFolder( mJournals, this );
01760
01761 mContacts = mCalendar = mNotes = mTasks = mJournals = 0;
01762 }
01763
01764 QString KMailICalIfaceImpl::folderPixmap( KFolderTreeItem::Type type ) const
01765 {
01766 if( !mUseResourceIMAP )
01767 return QString::null;
01768
01769 if( type == KFolderTreeItem::Contacts )
01770 return QString::fromLatin1( "kmgroupware_folder_contacts" );
01771 else if( type == KFolderTreeItem::Calendar )
01772 return QString::fromLatin1( "kmgroupware_folder_calendar" );
01773 else if( type == KFolderTreeItem::Notes )
01774 return QString::fromLatin1( "kmgroupware_folder_notes" );
01775 else if( type == KFolderTreeItem::Tasks )
01776 return QString::fromLatin1( "kmgroupware_folder_tasks" );
01777 else if( type == KFolderTreeItem::Journals )
01778 return QString::fromLatin1( "kmgroupware_folder_journals" );
01779
01780 return QString::null;
01781 }
01782
01783 static void reloadFolderTree()
01784 {
01785
01786 kmkernel->folderMgr()->contentsChanged();
01787 }
01788
01789
01790
01791
01792 static void vPartMicroParser( const QString& str, QString& s )
01793 {
01794 QString line;
01795 uint len = str.length();
01796
01797 for( uint i=0; i<len; ++i){
01798 if( str[i] == '\r' || str[i] == '\n' ){
01799 if( str[i] == '\r' )
01800 ++i;
01801 if( i+1 < len && str[i+1] == ' ' ){
01802
01803 ++i;
01804 }else{
01805
01806 if( line.startsWith( s ) ) {
01807 s = line.mid( s.length() + 1 );
01808 return;
01809 }
01810 line = "";
01811 }
01812 } else {
01813 line += str[i];
01814 }
01815 }
01816
01817
01818 s.truncate(0);
01819 }
01820
01821
01822 static KMFolder* findFolderByAnnotation( KMFolderDir* folderParentDir, const QString& annotation )
01823 {
01824 QPtrListIterator<KMFolderNode> it( *folderParentDir );
01825 for ( ; it.current(); ++it ) {
01826 if ( !it.current()->isDir() ) {
01827 KMFolder* folder = static_cast<KMFolder *>( it.current() );
01828 if ( folder->folderType() == KMFolderTypeCachedImap ) {
01829 QString folderAnnotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
01830
01831 if ( folderAnnotation == annotation )
01832 return folder;
01833 }
01834 }
01835 }
01836 return 0;
01837 }
01838
01839 KMailICalIfaceImpl::StandardFolderSearchResult KMailICalIfaceImpl::findStandardResourceFolder( KMFolderDir* folderParentDir, KMail::FolderContentsType contentsType )
01840 {
01841 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
01842 {
01843
01844 KMFolder* folder = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) + ".default" );
01845 if ( folder )
01846 return StandardFolderSearchResult( folder, StandardFolderSearchResult::FoundAndStandard );
01847
01848
01849 folder = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) );
01850 if ( folder )
01851 return StandardFolderSearchResult( folder, StandardFolderSearchResult::FoundByType );
01852
01853
01854 KMFolderNode* node = folderParentDir->hasNamedFolder( localizedDefaultFolderName( contentsType ) );
01855 if ( node && !node->isDir() )
01856 return StandardFolderSearchResult( static_cast<KMFolder *>( node ), StandardFolderSearchResult::FoundByName );
01857
01858 kdDebug(5006) << "findStandardResourceFolder: found no resource folder for " << s_folderContentsType[contentsType].annotation << endl;
01859 return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
01860 }
01861 else
01862 {
01863 KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
01864 unsigned int folderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
01865 if( folderLanguage > 3 ) folderLanguage = 0;
01866 KMFolderNode* node = folderParentDir->hasNamedFolder( folderName( itemType, folderLanguage ) );
01867 if ( !node || node->isDir() )
01868 return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
01869 return StandardFolderSearchResult( static_cast<KMFolder*>( node ), StandardFolderSearchResult::FoundAndStandard );
01870 }
01871 }
01872
01873 void KMailICalIfaceImpl::setResourceQuiet(bool q)
01874 {
01875 mResourceQuiet = q;
01876 }
01877
01878 bool KMailICalIfaceImpl::isResourceQuiet() const
01879 {
01880 return mResourceQuiet;
01881 }
01882
01883 #include "kmailicalifaceimpl.moc"