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
00074 static void vPartMicroParser( const QString& str, QString& s );
00075 static void reloadFolderTree();
00076
00077
00078 static const struct {
00079 const char* contentsTypeStr;
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
00128
00129
00130
00131
00132
00133
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
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
00153
00154
00155
00156
00157 static DwBodyPart* findBodyPartByMimeType( const KMMessage& msg, const char* sType, const char* sSubtype, bool startsWith = false )
00158 {
00159
00160
00161 DwBodyPart* part = msg.getFirstDwBodyPart();
00162 while( part ){
00163
00164
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
00183 static DwBodyPart* findBodyPart( const KMMessage& msg, const QString& attachmentName )
00184 {
00185
00186
00187 for ( DwBodyPart* part = msg.getFirstDwBodyPart(); part; part = part->Next() ) {
00188
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
00215
00216
00217
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
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
00255
00256
00257 newPart->Headers().ContentDisposition().Parse();
00258
00259 DwBodyPart* part = lookupByName ? findBodyPart( msg, attachmentName )
00260 : findBodyPartByMimeType( msg, sType, sSubtype );
00261 if ( part ) {
00262
00263
00264 newPart->SetNext( part->Next() );
00265
00266
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
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 );
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
00303
00304
00305
00306
00307
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
00316
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
00352
00353
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
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
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
00392
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
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
00423 msg->cleanupHeader();
00424
00425 msg->touch();
00426 if ( folder.addMsg( msg ) == 0 )
00427
00428 sernum = msg->getMsgSerNum();
00429 kdDebug(5006) << "addIncidenceKolab(): Message done and saved. Sernum: "
00430 << sernum << endl;
00431
00432
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
00444 if( !mUseResourceIMAP )
00445 return false;
00446
00447 kdDebug(5006) << "KMailICalIfaceImpl::deleteIncidenceKolab( "
00448 << resource << ", " << sernum << ")\n";
00449
00450
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
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
00538
00539
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
00546
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
00561
00562
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
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
00583
00584
00585 mAccumulators.remove( ac->folder );
00586 }
00587 } else {
00588
00589
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
00603 QValueList<KMailICalIfaceImpl::SubResource> KMailICalIfaceImpl::subresourcesKolab( const QString& contentsType )
00604 {
00605 QValueList<SubResource> subResources;
00606
00607
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
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
00659 bool KMailICalIfaceImpl::isWritableFolder( const QString& type,
00660 const QString& resource )
00661 {
00662 KMFolder* f = folderFromType( type, resource );
00663 if ( !f )
00664
00665 return false;
00666
00667 return !f->isReadOnly();
00668 }
00669
00670
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
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
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 );
00740
00741
00742
00743 for( QStringList::ConstIterator it = deletedAttachments.begin();
00744 it != deletedAttachments.end();
00745 ++it ){
00746 if( !deleteAttachment( *newMsg, *it ) ){
00747
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
00759 if ( !messageWasIcalVcardFormat ) {
00760 setIcalVcardContentTypeHeader( newMsg, t );
00761 }
00762 newMsg->setBodyEncoded( plainTextBody.utf8() );
00763 } else if ( storageFormat( f ) == StorageXML ) {
00764 if ( messageWasIcalVcardFormat ) {
00765
00766
00767 setXMLContentTypeHeader( newMsg, plainTextBody );
00768 }
00769
00770
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
00788
00789
00790 newMsg->cleanupHeader();
00791
00792
00793
00794 deleteMsg( msg );
00795 if ( f->addMsg( newMsg ) == 0 ) {
00796
00797 rc = newMsg->getMsgSerNum();
00798 kdDebug(5006) << "forget about " << sernum << ", it's " << rc << " now" << endl;
00799 }
00800 addFolderChange( f, Contents );
00801 } else {
00802
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
00818
00819
00820 if( !mUseResourceIMAP )
00821 return KURL();
00822
00823 kdDebug(5006) << "KMailICalIfaceImpl::getAttachment( "
00824 << resource << ", " << sernum << ", " << filename << " )\n";
00825
00826
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
00846
00847 DwBodyPart* part = findBodyPart( *msg, filename );
00848 if ( part ) {
00849
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
00876
00877
00878
00879 void KMailICalIfaceImpl::slotFolderRemoved( KMFolder* folder )
00880 {
00881
00882
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
00890 void KMailICalIfaceImpl::slotIncidenceAdded( KMFolder* folder,
00891 Q_UINT32 sernum )
00892 {
00893 if( mResourceQuiet || !mUseResourceIMAP )
00894 return;
00895
00896
00897 QString type = folderContentsType( folder->storage()->contentsType() );
00898 if( type.isEmpty() ) {
00899 kdError(5006) << "Not an IMAP resource folder" << endl;
00900 return;
00901 }
00902
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
00920 ok = vPartFoundAndDecoded( msg, s );
00921 if ( ok )
00922 vPartMicroParser( s, uid );
00923 break;
00924 case StorageXML:
00925
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
00942 if ( mInTransit.contains( uid ) ) {
00943 mInTransit.remove( uid );
00944 }
00945 incidenceAdded( type, folder->location(), sernum, format, s );
00946 } else {
00947
00948
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
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
00968 if( !type.isEmpty() ) {
00969
00970 int i = 0;
00971 KMFolder* aFolder = 0;
00972 KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
00973 assert( folder == aFolder );
00974
00975
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
01007 void KMailICalIfaceImpl::slotRefresh( const QString& type )
01008 {
01009 if( mUseResourceIMAP ) {
01010 signalRefresh( type, QString::null );
01011 kdDebug(5006) << "Emitting DCOP signal signalRefresh( " << type << " )" << endl;
01012 }
01013 }
01014
01015
01016 void KMailICalIfaceImpl::slotRefreshFolder( KMFolder* folder)
01017 {
01018
01019
01020
01021 if( mUseResourceIMAP && folder ) {
01022 if( folder == mCalendar || folder == mContacts
01023 || folder == mNotes || folder == mTasks
01024 || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
01025
01026 KMail::FolderContentsType ct = folder->storage()->contentsType();
01027 slotRefresh( s_folderContentsType[ct].contentsTypeStr );
01028 }
01029 }
01030 }
01031
01032
01033
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
01064
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
01097
01098 static QMap<KFolderTreeItem::Type,QString> folderNames[4];
01099 QString KMailICalIfaceImpl::folderName( KFolderTreeItem::Type type, int language ) const
01100 {
01101
01102 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
01103 language = 0;
01104
01105 static bool folderNamesSet = false;
01106 if( !folderNamesSet ) {
01107 folderNamesSet = true;
01108
01109
01110
01111
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
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
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
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
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
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
01184
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
01199
01200
01201
01202 if ( isStandardResourceFolder( folder ) )
01203 return;
01204
01205
01206 const QString location = folder->location();
01207 ExtraFolder* ef = mExtraFolders.find( location );
01208 if ( ef && ef->folder ) {
01209
01210 subresourceDeleted(folderContentsType( folder->storage()->contentsType() ), location );
01211
01212 if ( contentsType == 0 ) {
01213
01214 mExtraFolders.remove( location );
01215 folder->disconnect( this );
01216 return;
01217 }
01218
01219 } else {
01220 if ( ef && !ef->folder )
01221 mExtraFolders.remove( location );
01222 if ( contentsType == 0 )
01223 return;
01224
01225
01226
01227 ef = new ExtraFolder( folder );
01228 mExtraFolders.insert( location, ef );
01229
01230 FolderInfo info = readFolderInfo( folder );
01231 mFolderInfoMap.insert( folder, info );
01232
01233
01234
01235
01236
01237
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
01248 subresourceAdded( folderContentsType( contentsType ), location, folder->prettyURL() );
01249 }
01250
01251 KMFolder* KMailICalIfaceImpl::extraFolder( const QString& type,
01252 const QString& folder )
01253 {
01254
01255
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 {
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
01332
01333
01334
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
01350
01351
01352 KURL httpURL( folderURL );
01353
01354 httpURL.setProtocol( "https" );
01355 httpURL.setPort( 0 );
01356
01357
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
01367 path = path.mid( secondSlash );
01368 path.prepend( folderURL.user() );
01369 } else {
01370
01371
01372 path = path.mid( secondSlash );
01373 }
01374
01375 httpURL.setPath( "/freebusy/trigger/" + path + ".pfb" );
01376 httpURL.setQuery( QString::null );
01377
01378 httpURL = KURL( httpURL.url(0,106), 106 );
01379 kdDebug() << "Triggering PFB update for " << folderURL << " : getting " << httpURL << endl;
01380
01381
01382 KIO::get( httpURL, false, false );
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 );
01394
01395 }
01396 }
01397
01398
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
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
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
01437 ExtraFolder* ef = mExtraFolders.find( resource );
01438 if ( ef )
01439 return ef->folder;
01440
01441
01442 return 0;
01443 }
01444
01445
01446
01447
01448
01449 void KMailICalIfaceImpl::readConfig()
01450 {
01451 bool enabled = GlobalSettings::self()->theIMAPResourceEnabled();
01452
01453 if( !enabled ) {
01454 if( mUseResourceIMAP == true ) {
01455
01456 mUseResourceIMAP = false;
01457 cleanup();
01458 reloadFolderTree();
01459 }
01460 return;
01461 }
01462 mUseResourceIMAP = enabled;
01463
01464
01465 const bool hideFolders = GlobalSettings::self()->hideGroupwareFolders();
01466 QString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
01467
01468
01469 KMFolderDir* folderParentDir;
01470 KMFolderType folderType;
01471 KMFolder* folderParent = kmkernel->findFolderById( parentName );
01472 if( folderParent == 0 ) {
01473
01474
01475 kdDebug(5006) << "Groupware folder " << parentName << " not found. Groupware functionality disabled" << endl;
01476
01477 KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
01478 Q_ASSERT( account );
01479 if ( account ) {
01480
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
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
01500
01501 bool noneFound = true;
01502 bool mustFix = false;
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
01514 mustFix = true;
01515 }
01516 }
01517
01518
01519 if( mUseResourceIMAP && !noneFound && !mustFix && mFolderParentDir == folderParentDir
01520 && mFolderType == folderType ) {
01521
01522 if ( hideFolders != mHideFolders ) {
01523
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
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
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
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
01581 cleanup();
01582
01583
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
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
01603
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
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
01623
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
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
01646 if ( folderParent )
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
01659 KMFolderType type = mFolderType;
01660 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
01661
01662 KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
01663
01664
01665
01666 StandardFolderSearchResult result = findStandardResourceFolder( mFolderParentDir, contentsType );
01667 KMFolder* folder = result.folder;
01668
01669 if ( !folder ) {
01670
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
01679 setStorageFormat( folder, globalStorageFormat() );
01680 } else {
01681 FolderInfo info = readFolderInfo( folder );
01682 mFolderInfoMap.insert( folder, info );
01683
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
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
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
01773 kmkernel->folderMgr()->contentsChanged();
01774 }
01775
01776
01777
01778
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
01790 ++i;
01791 }else{
01792
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
01805 s.truncate(0);
01806 }
01807
01808
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
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
01831 KMFolder* folder = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) + ".default" );
01832 if ( folder )
01833 return StandardFolderSearchResult( folder, StandardFolderSearchResult::FoundAndStandard );
01834
01835
01836 folder = findFolderByAnnotation( folderParentDir, QString( s_folderContentsType[contentsType].annotation ) );
01837 if ( folder )
01838 return StandardFolderSearchResult( folder, StandardFolderSearchResult::FoundByType );
01839
01840
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
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"