kmail

kmailicalifaceimpl.cpp
1/*
2 This file is part of KMail.
3
4 Copyright (c) 2003 Steffen Hansen <steffen@klaralvdalens-datakonsult.se>
5 Copyright (c) 2003 - 2004 Bo Thorsen <bo@sonofthor.dk>
6 Copyright (c) 2004 Till Adam <adam@kde.org>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22
23 In addition, as a special exception, the copyright holders give
24 permission to link the code of this program with any edition of
25 the TQt library by Trolltech AS, Norway (or with modified versions
26 of TQt that use the same license as TQt), and distribute linked
27 combinations including the two. You must obey the GNU General
28 Public License in all respects for all of the code used other than
29 TQt. If you modify this file, you may extend this exception to
30 your version of the file, but you are not obligated to do so. If
31 you do not wish to do so, delete this exception statement from
32 your version.
33*/
34
35#ifdef HAVE_CONFIG_H
36#include <config.h>
37#endif
38
39#include "kmailicalifaceimpl.h"
40#include "kmfolder.h"
41#include "kmfoldertree.h"
42#include "kmfolderdir.h"
43#include "kmgroupware.h"
44#include "kmfoldermgr.h"
45#include "kmcommands.h"
46#include "kmfolderindex.h"
47#include "kmmsgdict.h"
48#include "kmmsgpart.h"
50#include "kmfolderimap.h"
51#include "globalsettings.h"
52#include "accountmanager.h"
53#include "kmfoldercachedimap.h"
54#include "kmacctcachedimap.h"
55#include "acljobs.h"
56
57#include "scalix.h"
58
59#include <mimelib/enum.h>
60#include <mimelib/utility.h>
61#include <mimelib/body.h>
62#include <mimelib/mimepp.h>
63
64#include <tqfile.h>
65#include <tqmap.h>
66#include <tqtextcodec.h>
67
68#include <kdebug.h>
69#include <kiconloader.h>
70#include <kinputdialog.h>
71#include <dcopclient.h>
72#include <tdemessagebox.h>
73#include <tdeconfig.h>
74#include <kurl.h>
75#include <tdetempfile.h>
76
77using namespace KMail;
78
79TQMap<TQString, TQString> *KMailICalIfaceImpl::mSubResourceUINamesMap = new TQMap<TQString, TQString>;
80
81// Local helper methods
82static void vPartMicroParser( const TQString& str, TQString& s );
83static void reloadFolderTree();
84
85// The index in this array is the KMail::FolderContentsType enum
86static const struct {
87 const char* contentsTypeStr; // the string used in the DCOP interface
88 const char* mimetype;
89 KFolderTreeItem::Type treeItemType;
90 const char* annotation;
91 const char* translatedName;
92} s_folderContentsType[] = {
93 { "Mail", "application/x-vnd.kolab.mail", KFolderTreeItem::Other, "mail", I18N_NOOP( "Mail" ) },
94 { "Calendar", "application/x-vnd.kolab.event", KFolderTreeItem::Calendar, "event", I18N_NOOP( "Calendar" ) },
95 { "Contact", "application/x-vnd.kolab.contact", KFolderTreeItem::Contacts, "contact", I18N_NOOP( "Contacts" ) },
96 { "Note", "application/x-vnd.kolab.note", KFolderTreeItem::Notes, "note", I18N_NOOP( "Notes" ) },
97 { "Task", "application/x-vnd.kolab.task", KFolderTreeItem::Tasks, "task", I18N_NOOP( "Tasks" ) },
98 { "Journal", "application/x-vnd.kolab.journal", KFolderTreeItem::Journals, "journal", I18N_NOOP( "Journal" ) }
99};
100
101static TQString folderContentsType( KMail::FolderContentsType type )
102{
103 return s_folderContentsType[type].contentsTypeStr;
104}
105
106static TQString folderKolabMimeType( KMail::FolderContentsType type )
107{
108 return s_folderContentsType[type].mimetype;
109}
110
111KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::globalStorageFormat() const {
112 return GlobalSettings::self()->theIMAPResourceStorageFormat()
113 == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
114}
115
116static KMail::FolderContentsType folderContentsType( const TQString& type )
117{
118 for ( uint i = 0 ; i < sizeof s_folderContentsType / sizeof *s_folderContentsType; ++i )
119 if ( type == s_folderContentsType[i].contentsTypeStr )
120 return static_cast<KMail::FolderContentsType>( i );
121 return KMail::ContentsTypeMail;
122}
123
124static TQString localizedDefaultFolderName( KMail::FolderContentsType type )
125{
126 return i18n( s_folderContentsType[type].translatedName );
127}
128
129const char* KMailICalIfaceImpl::annotationForContentsType( KMail::FolderContentsType type )
130{
131 return s_folderContentsType[type].annotation;
132}
133
134ExtraFolder::ExtraFolder( KMFolder* f )
135 : folder( f )
136{
137 folder->open("kmailicaliface::extrafolder");
138}
139
140ExtraFolder::~ExtraFolder()
141{
142 if ( folder )
143 folder->close("kmailicaliface::extrafolder");
144}
145
146
147/*
148 This interface has three parts to it - libkcal interface;
149 kmail interface; and helper functions.
150
151 The libkcal interface and the kmail interface have the same three
152 methods: add, delete and refresh. The only difference is that the
153 libkcal interface is used from the IMAP resource in libkcal and
154 the kmail interface is used from the groupware object in kmail.
155*/
156
157KMailICalIfaceImpl::KMailICalIfaceImpl()
158 : DCOPObject( "KMailICalIface" ), TQObject( 0, "KMailICalIfaceImpl" ),
159 mContacts( 0 ), mCalendar( 0 ), mNotes( 0 ), mTasks( 0 ), mJournals( 0 ),
160 mFolderLanguage( 0 ), mFolderParentDir( 0 ), mFolderType( KMFolderTypeUnknown ),
161 mUseResourceIMAP( false ), mResourceQuiet( false ), mHideFolders( true )
162{
163 // Listen to config changes
164 connect( kmkernel, TQ_SIGNAL( configChanged() ), this, TQ_SLOT( readConfig() ) );
165 connect( kmkernel, TQ_SIGNAL( folderRemoved( KMFolder* ) ),
166 this, TQ_SLOT( slotFolderRemoved( KMFolder* ) ) );
167
168 mExtraFolders.setAutoDelete( true );
169 mAccumulators.setAutoDelete( true );
170}
171
172
173/* libkcal part of the interface, called from the resources using this
174 * when incidences are added or deleted */
175
176// Helper function to find an attachment of a given mimetype
177// Can't use KMMessage::findDwBodyPart since it only works with known mimetypes.
178static DwBodyPart* findBodyPartByMimeType( const KMMessage& msg, const char* sType, const char* sSubtype, bool startsWith = false )
179{
180 // quickly searching for our message part: since Kolab parts are
181 // top-level parts we do *not* have to travel into embedded multiparts
182 DwBodyPart* part = msg.getFirstDwBodyPart();
183 while( part ){
184 // kdDebug() << part->Headers().ContentType().TypeStr().c_str() << " "
185 // << part->Headers().ContentType().SubtypeStr().c_str() << endl;
186 if ( part->hasHeaders() ) {
187 DwMediaType& contentType = part->Headers().ContentType();
188 if ( startsWith ) {
189 if ( contentType.TypeStr() == sType
190 && TQString( contentType.SubtypeStr().c_str() ).startsWith( sSubtype ) )
191 return part;
192 }
193 else
194 if ( contentType.TypeStr() == sType
195 && contentType.SubtypeStr() == sSubtype )
196 return part;
197 }
198 part = part->Next();
199 }
200 return 0;
201}
202
203// Helper function to find an attachment with a given filename
204static DwBodyPart* findBodyPart( const KMMessage& msg, const TQString& attachmentName )
205{
206 // quickly searching for our message part: since Kolab parts are
207 // top-level parts we do *not* have to travel into embedded multiparts
208 for ( DwBodyPart* part = msg.getFirstDwBodyPart(); part; part = part->Next() ) {
209 //kdDebug(5006) << "findBodyPart: - " << part->Headers().ContentDisposition().Filename().c_str() << endl;
210 if ( part->hasHeaders()
211 && attachmentName == part->Headers().ContentDisposition().Filename().c_str() )
212 return part;
213 if ( part->hasHeaders() && attachmentName == part->Headers().ContentType().Name().c_str() )
214 return part;
215 }
216 return 0;
217}
218
219#if 0
220static void debugBodyParts( const char* foo, const KMMessage& msg )
221{
222 kdDebug(5006) << "--debugBodyParts " << foo << "--" << endl;
223 for ( DwBodyPart* part = msg.getFirstDwBodyPart(); part; part = part->Next() ) {
224 if ( part->hasHeaders() ) {
225 kdDebug(5006) << " bodypart: " << part << endl;
226 kdDebug(5006) << " " << part->Headers().AsString().c_str() << endl;
227 }
228 else
229 kdDebug(5006) << " part " << part << " has no headers" << endl;
230 }
231}
232#else
233inline static void debugBodyParts( const char*, const KMMessage& ) {}
234#endif
235
236
237// Add (or overwrite, resp.) an attachment in an existing mail,
238// attachments must be local files, they are identified by their names.
239// If lookupByName if false the attachment to replace is looked up by mimetype.
240// return value: wrong if attachment could not be added/updated
241bool KMailICalIfaceImpl::updateAttachment( KMMessage& msg,
242 const TQString& attachmentURL,
243 const TQString& attachmentName,
244 const TQString& attachmentMimetype,
245 bool lookupByName )
246{
247 kdDebug(5006) << "KMailICalIfaceImpl::updateAttachment( " << attachmentURL << " )" << endl;
248
249 bool bOK = false;
250
251 KURL url( attachmentURL );
252 if ( url.isValid() && url.isLocalFile() ) {
253 const TQString fileName( url.path() );
254 TQFile file( fileName );
255 if( file.open( IO_ReadOnly ) ) {
256 TQByteArray rawData = file.readAll();
257 file.close();
258
259 // create the new message part with data read from temp file
260 KMMessagePart msgPart;
261 msgPart.setName( attachmentName );
262
263 const int iSlash = attachmentMimetype.find('/');
264 const TQCString sType = attachmentMimetype.left( iSlash ).latin1();
265 const TQCString sSubtype = attachmentMimetype.mid( iSlash+1 ).latin1();
266 msgPart.setTypeStr( sType );
267 msgPart.setSubtypeStr( sSubtype );
268 TQCString ctd("attachment;\n filename=\"");
269 ctd.append( attachmentName.latin1() );
270 ctd.append("\"");
271 msgPart.setContentDisposition( ctd );
272 TQValueList<int> dummy;
273 msgPart.setBodyAndGuessCte( rawData, dummy );
274 msgPart.setPartSpecifier( fileName );
275
276 DwBodyPart* newPart = msg.createDWBodyPart( &msgPart );
277 // This whole method is a bit special. We mix code for writing and code for reading.
278 // E.g. we need to parse the content-disposition again for ContentDisposition().Filename()
279 // to work later on.
280 newPart->Headers().ContentDisposition().Parse();
281
282 DwBodyPart* part = lookupByName ? findBodyPart( msg, attachmentName )
283 : findBodyPartByMimeType( msg, sType, sSubtype );
284 if ( part ) {
285 // Make sure the replacing body part is pointing
286 // to the same next part as the original body part.
287 newPart->SetNext( part->Next() );
288 // call DwBodyPart::operator =
289 // which calls DwEntity::operator =
290 *part = *newPart;
291 delete newPart;
292 msg.setNeedsAssembly();
293 kdDebug(5006) << "Attachment " << attachmentName << " updated." << endl;
294 } else {
295 msg.addDwBodyPart( newPart );
296 kdDebug(5006) << "Attachment " << attachmentName << " added." << endl;
297 }
298 bOK = true;
299 }else{
300 kdDebug(5006) << "Attachment " << attachmentURL << " can not be read." << endl;
301 }
302 }else{
303 kdDebug(5006) << "Attachment " << attachmentURL << " not a local file." << endl;
304 }
305
306 return bOK;
307}
308
309// Look for the attachment with the right mimetype
310bool KMailICalIfaceImpl::kolabXMLFoundAndDecoded( const KMMessage& msg, const TQString& mimetype, TQString& s )
311{
312 const int iSlash = mimetype.find('/');
313 const TQCString sType = mimetype.left( iSlash ).latin1();
314 const TQCString sSubtype = mimetype.mid( iSlash+1 ).latin1();
315 DwBodyPart* part = findBodyPartByMimeType( msg, sType, sSubtype, true /* starts with sSubtype, to accept application/x-vnd.kolab.contact.distlist */ );
316 if ( part ) {
317 KMMessagePart msgPart;
318 KMMessage::bodyPart(part, &msgPart);
319 s = msgPart.bodyToUnicode( TQTextCodec::codecForName( "utf8" ) );
320 return true;
321 }
322 return false;
323}
324
325// Delete an attachment in an existing mail.
326// return value: wrong if attachment could not be deleted
327//
328// This code could be optimized: for now we just replace
329// the attachment by an empty dummy attachment since Mimelib
330// does not provide an option for deleting attachments yet.
331bool KMailICalIfaceImpl::deleteAttachment( KMMessage& msg,
332 const TQString& attachmentName )
333{
334 kdDebug(5006) << "KMailICalIfaceImpl::deleteAttachment( " << attachmentName << " )" << endl;
335
336 bool bOK = false;
337
338 // quickly searching for our message part: since Kolab parts are
339 // top-level parts we do *not* have to travel into embedded multiparts
340 DwBodyPart* part = findBodyPart( msg, attachmentName );
341 if ( part ) {
342 msg.getTopLevelPart()->Body().RemoveBodyPart( part );
343 delete part;
344 msg.setNeedsAssembly();
345 kdDebug(5006) << "Attachment deleted." << endl;
346 bOK = true;
347 }
348
349 if( !bOK ){
350 kdDebug(5006) << "Attachment " << attachmentName << " not found." << endl;
351 }
352
353 return bOK;
354}
355
356static void setIcalVcardContentTypeHeader( KMMessage *msg, KMail::FolderContentsType t, KMFolder *folder )
357{
358 KMAcctCachedImap::GroupwareType groupwareType = KMAcctCachedImap::GroupwareKolab;
359
360 KMFolderCachedImap *imapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
361 if ( imapFolder )
362 groupwareType = imapFolder->account()->groupwareType();
363
364 msg->setType( DwMime::kTypeText );
365 if ( t == KMail::ContentsTypeCalendar || t == KMail::ContentsTypeTask
366 || t == KMail::ContentsTypeJournal ) {
367 msg->setSubtype( DwMime::kSubtypeVCal );
368
369 if ( groupwareType == KMAcctCachedImap::GroupwareKolab )
370 msg->setHeaderField("Content-Type",
371 "text/calendar; method=REQUEST; charset=\"utf-8\"");
372 else if ( groupwareType == KMAcctCachedImap::GroupwareScalix )
373 msg->setHeaderField("Content-Type",
374 "text/calendar; method=PUBLISH; charset=\"UTF-8\"");
375
376 } else if ( t == KMail::ContentsTypeContact ) {
377 msg->setSubtype( DwMime::kSubtypeXVCard );
378 if ( groupwareType == KMAcctCachedImap::GroupwareKolab )
379 msg->setHeaderField( "Content-Type", "Text/X-VCard; charset=\"utf-8\"" );
380 else if ( groupwareType == KMAcctCachedImap::GroupwareScalix )
381 msg->setHeaderField( "Content-Type", "application/scalix-properties; charset=\"UTF-8\"" );
382 } else {
383 kdWarning(5006) << k_funcinfo << "Attempt to write non-groupware contents to folder" << endl;
384 }
385}
386
387static void setXMLContentTypeHeader( KMMessage *msg, const TQString plainTextBody )
388{
389 // add a first body part to be displayed by all mailer
390 // than can NOT display Kolab data: no matter if these
391 // mailers are MIME compliant or not
392 KMMessagePart firstPart;
393 firstPart.setType( DwMime::kTypeText );
394 firstPart.setSubtype( DwMime::kSubtypePlain );
395 msg->removeHeaderField( "Content-Type" );
396 msg->setType( DwMime::kTypeMultipart );
397 msg->setSubtype( DwMime::kSubtypeMixed );
398 msg->headers().ContentType().CreateBoundary( 0 );
399 msg->headers().ContentType().Assemble();
400 firstPart.setBodyFromUnicode( plainTextBody );
401 msg->addBodyPart( &firstPart );
402}
403
404// Store a new entry that was received from the resource
405TQ_UINT32 KMailICalIfaceImpl::addIncidenceKolab( KMFolder& folder,
406 const TQString& subject,
407 const TQString& plainTextBody,
408 const TQMap<TQCString, TQString>& customHeaders,
409 const TQStringList& attachmentURLs,
410 const TQStringList& attachmentNames,
411 const TQStringList& attachmentMimetypes )
412{
413 kdDebug(5006) << "KMailICalIfaceImpl::addIncidenceKolab( " << attachmentNames << " )" << endl;
414
415 TQ_UINT32 sernum = 0;
416 bool bAttachOK = true;
417
418 // Make a new message for the incidence
419 KMMessage* msg = new KMMessage();
420 msg->initHeader();
421 msg->setSubject( subject );
422 msg->setAutomaticFields( true );
423
424 TQMap<TQCString, TQString>::ConstIterator ith = customHeaders.begin();
425 const TQMap<TQCString, TQString>::ConstIterator ithEnd = customHeaders.end();
426 for ( ; ith != ithEnd ; ++ith ) {
427 msg->setHeaderField( ith.key(), ith.data() );
428 }
429 // In case of the ical format, simply add the plain text content with the
430 // right content type
431 if ( storageFormat( &folder ) == StorageXML ) {
432 setXMLContentTypeHeader( msg, plainTextBody );
433 } else if ( storageFormat( &folder ) == StorageIcalVcard ) {
434 const KMail::FolderContentsType t = folder.storage()->contentsType();
435 setIcalVcardContentTypeHeader( msg, t, &folder );
436 msg->setBodyEncoded( plainTextBody.utf8() );
437 } else {
438 kdWarning(5006) << k_funcinfo << "Attempt to write to folder with unknown storage type" << endl;
439 }
440
441 Q_ASSERT( attachmentMimetypes.count() == attachmentURLs.count() );
442 Q_ASSERT( attachmentNames.count() == attachmentURLs.count() );
443 // Add all attachments by reading them from their temp. files
444 TQStringList::ConstIterator itmime = attachmentMimetypes.begin();
445 TQStringList::ConstIterator iturl = attachmentURLs.begin();
446 for( TQStringList::ConstIterator itname = attachmentNames.begin();
447 itname != attachmentNames.end()
448 && itmime != attachmentMimetypes.end()
449 && iturl != attachmentURLs.end();
450 ++itname, ++iturl, ++itmime ){
451 bool byname = !(*itmime).startsWith( "application/x-vnd.kolab." );
452 if( !updateAttachment( *msg, *iturl, *itname, *itmime, byname ) ){
453 kdWarning(5006) << "Attachment error, can not add Incidence." << endl;
454 bAttachOK = false;
455 break;
456 }
457 }
458
459 if( bAttachOK ){
460 // Mark the message as read and store it in the folder
461 msg->cleanupHeader();
462 //debugBodyParts( "after cleanup", *msg );
463 msg->touch();
464 if ( folder.addMsg( msg ) == 0 )
465 // Message stored
466 sernum = msg->getMsgSerNum();
467 kdDebug(5006) << "addIncidenceKolab(): Message done and saved. Sernum: "
468 << sernum << endl;
469
470 //debugBodyParts( "after addMsg", *msg );
471 addFolderChange( &folder, Contents );
472 syncFolder( &folder );
473 } else
474 kdError(5006) << "addIncidenceKolab(): Message *NOT* saved!\n";
475
476 return sernum;
477}
478
479bool KMailICalIfaceImpl::deleteIncidenceKolab( const TQString& resource,
480 TQ_UINT32 sernum )
481{
482 // Find the message from the serial number and delete it.
483 if( !mUseResourceIMAP )
484 return false;
485
486 kdDebug(5006) << "KMailICalIfaceImpl::deleteIncidenceKolab( "
487 << resource << ", " << sernum << ")\n";
488
489 // Find the folder
490 KMFolder* f = findResourceFolder( resource );
491 if( !f ) {
492 kdError(5006) << "deleteIncidenceKolab(" << resource << ") : Not an IMAP resource folder" << endl;
493 return false;
494 }
495
496 bool rc = false;
497
498 KMMessage* msg = findMessageBySerNum( sernum, f );
499 if( msg ) {
500 // Message found - delete it and return happy
501 deleteMsg( msg );
502 syncFolder( f );
503 rc = true;
504 } else {
505 kdDebug(5006) << "Message not found, cannot remove serNum " << sernum << endl;
506 }
507 return rc;
508}
509
510
511int KMailICalIfaceImpl::incidencesKolabCount( const TQString& mimetype,
512 const TQString& resource )
513{
514 Q_UNUSED( mimetype ); // honouring that would be too slow...
515
516 if( !mUseResourceIMAP )
517 return 0;
518
519 KMFolder* f = findResourceFolder( resource );
520 if( !f ) {
521 kdError(5006) << "incidencesKolab(" << resource << ") : Not an IMAP resource folder" << endl;
522 return 0;
523 }
524
525 f->open("kolabcount");
526 int n = f->count();
527 f->close("kolabcount");
528 kdDebug(5006) << "KMailICalIfaceImpl::incidencesKolabCount( "
529 << resource << " ) returned " << n << endl;
530 return n;
531}
532
533TQMap<TQ_UINT32, TQString> KMailICalIfaceImpl::incidencesKolab( const TQString& mimetype,
534 const TQString& resource,
535 int startIndex,
536 int nbMessages )
537{
541
542 TQMap<TQ_UINT32, TQString> aMap;
543 if( !mUseResourceIMAP )
544 return aMap;
545
546 KMFolder* f = findResourceFolder( resource );
547 if( !f ) {
548 kdError(5006) << "incidencesKolab(" << resource << ") : Not an IMAP resource folder" << endl;
549 return aMap;
550 }
551
552 f->open( "incidences" );
553
554 kdDebug(5006) << k_funcinfo << "Getting incidences (" << mimetype << ") for folder " << f->label()
555 << ", starting with index " << startIndex << ", " << nbMessages << " messages." << endl;
556 kdDebug(5006) << "The folder has " << f->count() << " messages." << endl;
557
558 int stopIndex = nbMessages == -1 ? f->count() :
559 TQMIN( f->count(), startIndex + nbMessages );
560
561 for(int i = startIndex; i < stopIndex; ++i) {
562#if 0
563 bool unget = !f->isMessage(i);
564 KMMessage* msg = f->getMsg( i );
565#else // faster
566 KMMessage* msg = f->storage()->readTemporaryMsg(i);
567#endif
568 if ( msg ) {
569 const int iSlash = mimetype.find('/');
570 const TQCString sType = mimetype.left( iSlash ).latin1();
571 const TQCString sSubtype = mimetype.mid( iSlash+1 ).latin1();
572 if ( sType.isEmpty() || sSubtype.isEmpty() ) {
573 kdError(5006) << mimetype << " not an type/subtype combination" << endl;
574 } else {
575 DwBodyPart* dwPart = findBodyPartByMimeType( *msg, sType, sSubtype );
576 if ( dwPart ) {
577 KMMessagePart msgPart;
578 KMMessage::bodyPart(dwPart, &msgPart);
579 aMap.insert(msg->getMsgSerNum(), msgPart.bodyToUnicode( TQTextCodec::codecForName( "utf8" ) ));
580 } else {
581 // Check if the whole message has the right types. This is what
582 // happens in the case of ical storage, where the whole mail is
583 // the data
584 const TQCString type( msg->typeStr() );
585 const TQCString subtype( msg->subtypeStr() );
586 if (type.lower() == sType && subtype.lower() == sSubtype ) {
587 aMap.insert( msg->getMsgSerNum(), msg->bodyToUnicode() );
588 }
589 // This is *not* an error: it may be that not all of the messages
590 // have a message part that is matching the wanted MIME type
591 }
592 }
593#if 0
594 if( unget ) f->unGetMsg(i);
595#else
596 delete msg;
597#endif
598 } else {
599 kdDebug(5006) << k_funcinfo << " Unable to retrieve message " << i << " for incidence!" << endl;
600 }
601 }
602 f->close( "incidences" );
603 return aMap;
604}
605
606
607/* Called when a message that was downloaded from an online imap folder
608 * arrives. Needed when listing incidences on online account folders. */
609// TODO: Till, port me
610void KMailICalIfaceImpl::slotMessageRetrieved( KMMessage* msg )
611{
612 if( !msg ) return;
613
614 KMFolder *parent = msg->parent();
615 Q_ASSERT( parent );
616 TQ_UINT32 sernum = msg->getMsgSerNum();
617
618 // do we have an accumulator for this folder?
619 Accumulator *ac = mAccumulators.find( parent->location() );
620 if( ac ) {
621 TQString s;
622 if ( !vPartFoundAndDecoded( msg, s ) ) return;
623 TQString uid( "UID" );
624 vPartMicroParser( s, uid );
625 const TQ_UINT32 sernum = msg->getMsgSerNum();
626 mUIDToSerNum.insert( uid, sernum );
627 ac->add( s );
628 if( ac->isFull() ) {
629 /* if this was the last one we were waiting for, tell the resource
630 * about the new incidences and clean up. */
631 //asyncLoadResult( ac->incidences, ac->type, ac->folder );
632 mAccumulators.remove( ac->folder ); // autodelete
633 }
634 } else {
635 /* We are not accumulating for this folder, so this one was added
636 * by KMail. Do your thang. */
637 slotIncidenceAdded( msg->parent(), msg->getMsgSerNum() );
638 }
639
640 if ( mTheUnGetMes.contains( sernum ) ) {
641 mTheUnGetMes.remove( sernum );
642 int i = 0;
643 KMFolder* folder = 0;
644 KMMsgDict::instance()->getLocation( sernum, &folder, &i );
645 folder->unGetMsg( i );
646 }
647}
648
649static int dimapAccountCount()
650{
651 KMail::AccountManager *mgr = kmkernel->acctMgr();
652 KMAccount *account = mgr->first();
653 int count = 0;
654 while ( account ) {
655 if ( dynamic_cast<KMAcctCachedImap*>( account ) )
656 ++count;
657 account = mgr->next();
658 }
659 return count;
660}
661
662int KMailICalIfaceImpl::dimapAccounts()
663{
664 return dimapAccountCount();
665}
666
667static TQString subresourceLabelForPresentation( const KMFolder * folder )
668{
669 if( KMailICalIfaceImpl::getResourceMap()->contains( folder->location() ) ) {
670 return folder->label();
671 }
672
673 TQString label = folder->prettyURL();
674 TQStringList parts = TQStringList::split( TQString::fromLatin1("/"), label );
675
676 // In the common special case of some other user's folder shared with us
677 // the url looks like "Server Name/user/$USERNAME/Folder/Name". Make
678 // those a bit nicer.
679 if ( parts[1] == TQString::fromLatin1("user") ) {
680 TQStringList remainder(parts);
681 remainder.pop_front();
682 remainder.pop_front();
683 remainder.pop_front();
684 label = i18n("%1's %2")
685 .arg( parts[2] )
686 .arg( remainder.join( TQString::fromLatin1("/") ) );
687 }
688 // Another special case is our own folders, under the imap INBOX, make
689 // those prettier too
690 const KMFolder *parent = folder;
691 while ( parent->parent() && parent->parent()->owner() ) {
692 parent = parent->parent()->owner();
693 if ( parent->isSystemFolder() ) {
694 TQStringList remainder(parts);
695 remainder.pop_front();
696 remainder.pop_front();
697 if ( dimapAccountCount() > 1 ) {
698 // Fix kolab issue 2531 folder->storage() )->account() can be null
699 if( folder->storage() && static_cast<const KMFolderCachedImap*>( folder->storage() )->account() ) {
700 label = i18n( "My %1 (%2)")
701 .arg( remainder.join( TQString::fromLatin1("/") ),
702 static_cast<const KMFolderCachedImap*>( folder->storage() )->account()->name() );
703 } else {
704 label = i18n("My %1")
705 .arg( remainder.join( TQString::fromLatin1("/") ) );
706 }
707 } else {
708 label = i18n("My %1")
709 .arg( remainder.join( TQString::fromLatin1("/") ) );
710 }
711 break;
712 }
713 }
714 return label;
715}
716
717/* list all available subresources */
718TQValueList<KMailICalIfaceImpl::SubResource> KMailICalIfaceImpl::subresourcesKolab( const TQString& contentsType )
719{
720 TQValueList<SubResource> subResources;
721
722 // Add the default one
723 KMFolder* f = folderFromType( contentsType, TQString() );
724 if ( f ) {
725 subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
726 f->isWritable(), folderIsAlarmRelevant( f ) ) );
727 kdDebug(5006) << "Adding(1) folder " << f->location() << " " <<
728 ( !f->isWritable() ? "readonly" : "" ) << endl;
729 }
730
731 // get the extra ones
732 const KMail::FolderContentsType t = folderContentsType( contentsType );
733 TQDictIterator<ExtraFolder> it( mExtraFolders );
734 for ( ; it.current(); ++it ){
735 f = it.current()->folder;
736 if ( f && f->storage()->contentsType() == t ) {
737 subResources.append( SubResource( f->location(), subresourceLabelForPresentation( f ),
738 f->isWritable(), folderIsAlarmRelevant( f ) ) );
739 kdDebug(5006) << "Adding(2) folder " << f->location() << " " <<
740 ( !f->isWritable() ? "readonly" : "" ) << endl;
741 }
742 }
743
744 if ( subResources.isEmpty() )
745 kdDebug(5006) << "subresourcesKolab: No folder found for " << contentsType << endl;
746 return subResources;
747}
748
749bool KMailICalIfaceImpl::triggerSync( const TQString& contentsType )
750{
751 kdDebug(5006) << k_funcinfo << endl;
752 TQValueList<KMailICalIfaceImpl::SubResource> folderList = subresourcesKolab( contentsType );
753 for ( TQValueList<KMailICalIfaceImpl::SubResource>::const_iterator it( folderList.begin() ),
754 end( folderList.end() );
755 it != end ; ++it ) {
756 KMFolder * const f = findResourceFolder( (*it).location );
757 if ( !f ) continue;
758 if ( f->folderType() == KMFolderTypeImap || f->folderType() == KMFolderTypeCachedImap ) {
759 if ( !kmkernel->askToGoOnline() ) {
760 return false;
761 }
762 }
763
764 if ( f->folderType() == KMFolderTypeImap ) {
765 KMFolderImap *imap = static_cast<KMFolderImap*>( f->storage() );
766 imap->getAndCheckFolder();
767 } else if ( f->folderType() == KMFolderTypeCachedImap ) {
768 KMFolderCachedImap* cached = static_cast<KMFolderCachedImap*>( f->storage() );
769 if ( cached->account() ) {
770 cached->account()->processNewMailInFolder( f );
771 }
772 }
773 }
774 return true;
775}
776
777/* Used by the resource to query whether folders are writable. */
778bool KMailICalIfaceImpl::isWritableFolder( const TQString& type,
779 const TQString& resource )
780{
781 KMFolder* f = folderFromType( type, resource );
782 if ( !f )
783 // Definitely not writable
784 return false;
785
786 return f->isWritable();
787}
788
789/* Used by the resource to query the storage format of the folder. */
790KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( const TQString& resource )
791{
792 StorageFormat format;
793 KMFolder* f = findResourceFolder( resource );
794 if ( f )
795 format = storageFormat( f );
796 else
797 format = globalStorageFormat();
798 return format;
799}
800
815TQ_UINT32 KMailICalIfaceImpl::update( const TQString& resource,
816 TQ_UINT32 sernum,
817 const TQString& subject,
818 const TQString& plainTextBody,
819 const TQMap<TQCString, TQString>& customHeaders,
820 const TQStringList& attachmentURLs,
821 const TQStringList& attachmentMimetypes,
822 const TQStringList& attachmentNames,
823 const TQStringList& deletedAttachments )
824{
825 TQ_UINT32 rc = 0;
826
827 if( !mUseResourceIMAP )
828 return rc;
829
830 Q_ASSERT( !resource.isEmpty() );
831
832 kdDebug(5006) << "KMailICalIfaceImpl::update( " << resource << ", " << sernum << " )\n";
833 kdDebug(5006) << attachmentURLs << "\n";
834 kdDebug(5006) << attachmentMimetypes << "\n";
835 kdDebug(5006) << attachmentNames << "\n";
836 kdDebug(5006) << "deleted attachments:" << deletedAttachments << "\n";
837
838 // Find the folder
839 KMFolder* f = findResourceFolder( resource );
840 if( !f ) {
841 kdError(5006) << "update(" << resource << ") : Not an IMAP resource folder" << endl;
842 return rc;
843 }
844
845 f->open( "ifaceupdate" );
846
847 KMMessage* msg = 0;
848 if ( sernum != 0 ) {
849 msg = findMessageBySerNum( sernum, f );
850 if ( !msg ) return 0;
851 // Message found - make a copy and update it:
852 KMMessage* newMsg = new KMMessage( *msg );
853 newMsg->setSubject( subject );
854 TQMap<TQCString, TQString>::ConstIterator ith = customHeaders.begin();
855 const TQMap<TQCString, TQString>::ConstIterator ithEnd = customHeaders.begin();
856 for ( ; ith != ithEnd ; ++ith )
857 newMsg->setHeaderField( ith.key(), ith.data() );
858 newMsg->setParent( 0 ); // workaround strange line in KMMsgBase::assign. newMsg is not in any folder yet.
859 // Note that plainTextBody isn't used in this branch. We assume it's still valid from when the mail was created.
860
861 // Delete some attachments according to list
862 for( TQStringList::ConstIterator it = deletedAttachments.begin();
863 it != deletedAttachments.end();
864 ++it ){
865 if( !deleteAttachment( *newMsg, *it ) ){
866 // Note: It is _not_ an error if an attachment was already deleted.
867 }
868 }
869
870 const KMail::FolderContentsType t = f->storage()->contentsType();
871 const TQCString type = msg->typeStr();
872 const TQCString subtype = msg->subtypeStr();
873 const bool messageWasIcalVcardFormat = ( type.lower() == "text" &&
874 ( subtype.lower() == "calendar" || subtype.lower() == "x-vcard" ) );
875
876 if ( storageFormat( f ) == StorageIcalVcard ) {
877 //kdDebug(5006) << k_funcinfo << " StorageFormatIcalVcard " << endl;
878 if ( !messageWasIcalVcardFormat ) {
879 setIcalVcardContentTypeHeader( newMsg, t, f );
880 }
881 newMsg->setBodyEncoded( plainTextBody.utf8() );
882 } else if ( storageFormat( f ) == StorageXML ) {
883 if ( messageWasIcalVcardFormat ) {
884 // this was originally an ical event, but the folder changed to xml,
885 // convert
886 setXMLContentTypeHeader( newMsg, plainTextBody );
887 }
888 //kdDebug(5006) << k_funcinfo << " StorageFormatXML " << endl;
889 // Add all attachments by reading them from their temp. files
890 TQStringList::ConstIterator iturl = attachmentURLs.begin();
891 TQStringList::ConstIterator itmime = attachmentMimetypes.begin();
892 TQStringList::ConstIterator itname = attachmentNames.begin();
893 for( ;
894 iturl != attachmentURLs.end()
895 && itmime != attachmentMimetypes.end()
896 && itname != attachmentNames.end();
897 ++iturl, ++itname, ++itmime ){
898 bool byname = !(*itmime).startsWith( "application/x-vnd.kolab." );
899 if( !updateAttachment( *newMsg, *iturl, *itname, *itmime, byname ) ){
900 kdDebug(5006) << "Attachment error, can not update attachment " << *iturl << endl;
901 break;
902 }
903 }
904 }
905
906 //debugBodyParts( "in update, before cleanup", *newMsg );
907
908 // This is necessary for the headers to be readable later on
909 newMsg->cleanupHeader();
910
911 //debugBodyParts( "in update, after cleanup", *newMsg );
912
913 deleteMsg( msg );
914 if ( f->addMsg( newMsg ) == 0 ) {
915 // Message stored
916 rc = newMsg->getMsgSerNum();
917 kdDebug(5006) << "forget about " << sernum << ", it's " << rc << " now" << endl;
918 }
919 addFolderChange( f, Contents );
920 syncFolder( f );
921 } else {
922 // Message not found - store it newly
923 rc = addIncidenceKolab( *f, subject, plainTextBody, customHeaders,
924 attachmentURLs,
925 attachmentNames,
926 attachmentMimetypes );
927 }
928
929 f->close("ifaceupdate");
930 return rc;
931}
932
933KURL KMailICalIfaceImpl::getAttachment( const TQString& resource,
934 TQ_UINT32 sernum,
935 const TQString& filename )
936{
937 // This finds the attachment with the filename, saves it to a
938 // temp file and returns a URL to it. It's up to the resource
939 // to delete the tmp file later.
940 if( !mUseResourceIMAP )
941 return KURL();
942
943 kdDebug(5006) << "KMailICalIfaceImpl::getAttachment( "
944 << resource << ", " << sernum << ", " << filename << " )\n";
945
946 // Find the folder
947 KMFolder* f = findResourceFolder( resource );
948 if( !f ) {
949 kdError(5006) << "getAttachment(" << resource << ") : Not an IMAP resource folder" << endl;
950 return KURL();
951 }
952 if ( storageFormat( f ) != StorageXML ) {
953 kdError(5006) << "getAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
954 return KURL();
955 }
956
957 KURL url;
958
959 bool bOK = false;
960 bool quiet = mResourceQuiet;
961 mResourceQuiet = true;
962
963 KMMessage* msg = findMessageBySerNum( sernum, f );
964 if( msg ) {
965 // Message found - look for the attachment:
966
967 DwBodyPart* part = findBodyPart( *msg, filename );
968 if ( part ) {
969 // Save the contents of the attachment.
970 KMMessagePart aPart;
971 msg->bodyPart( part, &aPart );
972 TQByteArray rawData( aPart.bodyDecodedBinary() );
973
974 KTempFile file;
975 file.file()->writeBlock( rawData.data(), rawData.size() );
976
977 url.setPath( file.name() );
978
979 bOK = true;
980 }
981
982 if( !bOK ){
983 kdDebug(5006) << "Attachment " << filename << " not found." << endl;
984 }
985 }else{
986 kdDebug(5006) << "Message not found." << endl;
987 }
988
989 mResourceQuiet = quiet;
990 return url;
991}
992
993TQString KMailICalIfaceImpl::attachmentMimetype( const TQString & resource,
994 TQ_UINT32 sernum,
995 const TQString & filename )
996{
997 if( !mUseResourceIMAP )
998 return TQString();
999 KMFolder* f = findResourceFolder( resource );
1000 if( !f || storageFormat( f ) != StorageXML ) {
1001 kdError(5006) << "attachmentMimetype(" << resource << ") : Wrong folder" << endl;
1002 return TQString();
1003 }
1004
1005 KMMessage* msg = findMessageBySerNum( sernum, f );
1006 if( msg ) {
1007 // Message found - look for the attachment:
1008 DwBodyPart* part = findBodyPart( *msg, filename );
1009 if ( part ) {
1010 KMMessagePart kmPart;
1011 msg->bodyPart( part, &kmPart );
1012 return TQString( kmPart.typeStr() ) + "/" + TQString( kmPart.subtypeStr() );
1013 } else {
1014 kdDebug(5006) << "Attachment " << filename << " not found." << endl;
1015 }
1016 } else {
1017 kdDebug(5006) << "Message not found." << endl;
1018 }
1019
1020 return TQString();
1021}
1022
1023TQStringList KMailICalIfaceImpl::listAttachments(const TQString & resource, TQ_UINT32 sernum)
1024{
1025 TQStringList rv;
1026 if( !mUseResourceIMAP )
1027 return rv;
1028
1029 // Find the folder
1030 KMFolder* f = findResourceFolder( resource );
1031 if( !f ) {
1032 kdError(5006) << "listAttachments(" << resource << ") : Not an IMAP resource folder" << endl;
1033 return rv;
1034 }
1035 if ( storageFormat( f ) != StorageXML ) {
1036 kdError(5006) << "listAttachment(" << resource << ") : Folder has wrong storage format " << storageFormat( f ) << endl;
1037 return rv;
1038 }
1039
1040 KMMessage* msg = findMessageBySerNum( sernum, f );
1041 if( msg ) {
1042 for ( DwBodyPart* part = msg->getFirstDwBodyPart(); part; part = part->Next() ) {
1043 if ( part->hasHeaders() ) {
1044 TQString name;
1045 DwMediaType& contentType = part->Headers().ContentType();
1046 if ( TQString( contentType.SubtypeStr().c_str() ).startsWith( "x-vnd.kolab." )
1047 || TQString( contentType.SubtypeStr().c_str() ).contains( "tnef" ) )
1048 continue;
1049 if ( !part->Headers().ContentDisposition().Filename().empty() )
1050 name = part->Headers().ContentDisposition().Filename().c_str();
1051 else if ( !contentType.Name().empty() )
1052 name = contentType.Name().c_str();
1053 if ( !name.isEmpty() )
1054 rv.append( name );
1055 }
1056 }
1057 } else {
1058 kdDebug(5006) << "Message not found." << endl;
1059 }
1060
1061 return rv;
1062}
1063
1064
1065// ============================================================================
1066
1067/* KMail part of the interface. These slots are connected to the resource
1068 * folders and inform us of folders or incidences in them changing, being
1069 * added or going away. */
1070
1071void KMailICalIfaceImpl::slotFolderRemoved( KMFolder* folder )
1072{
1073 // pretend the folder just changed back to the mail type, which
1074 // does the right thing, namely remove resource
1075 folderContentsTypeChanged( folder, KMail::ContentsTypeMail );
1076 TDEConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
1077 configGroup.deleteEntry( folder->idString() + "-storageFormat" );
1078 configGroup.deleteEntry( folder->idString() + "-changes" );
1079}
1080
1081// KMail added a file to one of the groupware folders
1082void KMailICalIfaceImpl::slotIncidenceAdded( KMFolder* folder,
1083 TQ_UINT32 sernum )
1084{
1085 if( mResourceQuiet || !mUseResourceIMAP )
1086 return;
1087
1088// kdDebug(5006) << "KMailICalIfaceImpl::slotIncidenceAdded" << endl;
1089 TQString type = folderContentsType( folder->storage()->contentsType() );
1090 if( type.isEmpty() ) {
1091 kdError(5006) << "Not an IMAP resource folder" << endl;
1092 return;
1093 }
1094 // Get the index of the mail
1095 int i = 0;
1096 KMFolder* aFolder = 0;
1097 KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
1098 assert( folder == aFolder );
1099
1100 bool unget = !folder->isMessage( i );
1101 TQString s;
1102 TQString uid( "UID" );
1103 KMMessage *msg = folder->getMsg( i );
1104 if( !msg ) return;
1105 if( msg->isComplete() ) {
1106
1107 bool ok = false;
1108 StorageFormat format = storageFormat( folder );
1109 switch( format ) {
1110 case StorageIcalVcard:
1111 // Read the iCal or vCard
1112 ok = vPartFoundAndDecoded( msg, s );
1113 if ( ok )
1114 vPartMicroParser( s, uid );
1115 break;
1116 case StorageXML:
1117 // Read the XML from the attachment with the given mimetype
1118 if ( kolabXMLFoundAndDecoded( *msg,
1119 folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
1120 uid = msg->subject();
1121 ok = true;
1122 }
1123 break;
1124 }
1125 if ( !ok ) {
1126 if ( unget )
1127 folder->unGetMsg( i );
1128 return;
1129 }
1130 const TQ_UINT32 sernum = msg->getMsgSerNum();
1131 mUIDToSerNum.insert( uid, sernum );
1132
1133 // tell the resource if we didn't trigger this ourselves
1134 if ( mInTransit.contains( uid ) ) {
1135 mInTransit.remove( uid );
1136 }
1137 incidenceAdded( type, folder->location(), sernum, format, s );
1138 } else {
1139 // go get the rest of it, then try again
1140 // TODO: Till, port me
1141 if ( unget ) mTheUnGetMes.insert( msg->getMsgSerNum(), true );
1142 FolderJob *job = msg->parent()->createJob( msg );
1143 connect( job, TQ_SIGNAL( messageRetrieved( KMMessage* ) ),
1144 this, TQ_SLOT( slotMessageRetrieved( KMMessage* ) ) );
1145 job->start();
1146 return;
1147 }
1148 if( unget ) folder->unGetMsg(i);
1149}
1150
1151// KMail deleted a file
1152void KMailICalIfaceImpl::slotIncidenceDeleted( KMFolder* folder,
1153 TQ_UINT32 sernum )
1154{
1155 if( mResourceQuiet || !mUseResourceIMAP )
1156 return;
1157
1158 TQString type = folderContentsType( folder->storage()->contentsType() );
1159 //kdDebug(5006) << folder << " " << type << " " << sernum << endl;
1160 if( !type.isEmpty() ) {
1161 // Get the index of the mail
1162 int i = 0;
1163 KMFolder* aFolder = 0;
1164 KMMsgDict::instance()->getLocation( sernum, &aFolder, &i );
1165 assert( folder == aFolder );
1166
1167 // Read the iCal or vCard
1168 bool unget = !folder->isMessage( i );
1169 TQString s;
1170 bool ok = false;
1171 KMMessage* msg = folder->getMsg( i );
1172 TQString uid( "UID" );
1173 switch( storageFormat( folder ) ) {
1174 case StorageIcalVcard:
1175 if( vPartFoundAndDecoded( msg, s ) ) {
1176 vPartMicroParser( s, uid );
1177 ok = true;
1178 }
1179 break;
1180 case StorageXML:
1181 if ( kolabXMLFoundAndDecoded( *msg, folderKolabMimeType( folder->storage()->contentsType() ), s ) ) {
1182 uid = msg->subject();
1183 ok = true;
1184 }
1185 break;
1186 }
1187 if ( ok ) {
1188 kdDebug(5006) << "Emitting DCOP signal incidenceDeleted( "
1189 << type << ", " << folder->location() << ", " << uid
1190 << " )" << endl;
1191 incidenceDeleted( type, folder->location(), uid );
1192 }
1193 if( unget ) folder->unGetMsg(i);
1194 } else
1195 kdError(5006) << "Not a groupware folder" << endl;
1196}
1197
1198// KMail orders a refresh
1199void KMailICalIfaceImpl::slotRefresh( const TQString& type )
1200{
1201 if( mUseResourceIMAP ) {
1202 signalRefresh( type, TQString() /* PENDING(bo) folder->location() */ );
1203 kdDebug(5006) << "Emitting DCOP signal signalRefresh( " << type << " )" << endl;
1204 }
1205}
1206
1207// This is among other things called when an expunge of a folder happens
1208void KMailICalIfaceImpl::slotRefreshFolder( KMFolder* folder)
1209{
1210 // TODO: The resources would of course be better off, if only this
1211 // folder would need refreshing. Currently it just orders a reload of
1212 // the type of the folder
1213 if( mUseResourceIMAP && folder ) {
1214 if( folder == mCalendar || folder == mContacts
1215 || folder == mNotes || folder == mTasks
1216 || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
1217 // Refresh the folder of this type
1218 KMail::FolderContentsType ct = folder->storage()->contentsType();
1219 slotRefresh( s_folderContentsType[ct].contentsTypeStr );
1220 }
1221 }
1222}
1223
1224/****************************
1225 * The folder and message stuff code
1226 */
1227
1229 const TQString& folder )
1230{
1231 if( mUseResourceIMAP ) {
1232 KMFolder* f = 0;
1233 if ( !folder.isEmpty() ) {
1234 f = extraFolder( type, folder );
1235 if ( f )
1236 return f;
1237 }
1238
1239 if( type == "Calendar" ) f = mCalendar;
1240 else if( type == "Contact" ) f = mContacts;
1241 else if( type == "Note" ) f = mNotes;
1242 else if( type == "Task" || type == "Todo" ) f = mTasks;
1243 else if( type == "Journal" ) f = mJournals;
1244
1245 if ( f && ( folder.isEmpty() || folder == f->location() ) )
1246 return f;
1247
1248 kdError(5006) << "No folder ( " << type << ", " << folder << " )\n";
1249 }
1250
1251 return 0;
1252}
1253
1254
1255// Returns true if folder is a resource folder. If the resource isn't enabled
1256// this always returns false
1258{
1259 return mUseResourceIMAP && folder &&
1260 ( isStandardResourceFolder( folder ) || mExtraFolders.find( folder->location() )!=0 );
1261}
1262
1263bool KMailICalIfaceImpl::isStandardResourceFolder( KMFolder* folder ) const
1264{
1265 return ( folder == mCalendar || folder == mTasks || folder == mJournals ||
1266 folder == mNotes || folder == mContacts );
1267}
1268
1270{
1271 return mHideFolders && isResourceFolder( folder );
1272}
1273
1275{
1276 KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
1277 bool hide = dimapFolder && mHideFolders
1278 && (int)dimapFolder->account()->id() == GlobalSettings::self()->theIMAPResourceAccount()
1279 && GlobalSettings::self()->showOnlyGroupwareFoldersForGroupwareAccount();
1280 return hide;
1281
1282}
1283
1284KFolderTreeItem::Type KMailICalIfaceImpl::folderType( KMFolder* folder ) const
1285{
1286 if( mUseResourceIMAP && folder ) {
1287 if( folder == mCalendar || folder == mContacts
1288 || folder == mNotes || folder == mTasks
1289 || folder == mJournals || mExtraFolders.find( folder->location() ) ) {
1290 KMail::FolderContentsType ct = folder->storage()->contentsType();
1291 return s_folderContentsType[ct].treeItemType;
1292 }
1293 }
1294
1295 return KFolderTreeItem::Other;
1296}
1297
1298// Global tables of foldernames is different languages
1299// For now: 0->English, 1->German, 2->French, 3->Dutch
1300static TQMap<KFolderTreeItem::Type,TQString> folderNames[4];
1301TQString KMailICalIfaceImpl::folderName( KFolderTreeItem::Type type, int language ) const
1302{
1303 // With the XML storage, folders are always (internally) named in English
1304 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
1305 language = 0;
1306
1307 static bool folderNamesSet = false;
1308 if( !folderNamesSet ) {
1309 folderNamesSet = true;
1310 /* NOTE: If you add something here, you also need to update
1311 GroupwarePage in configuredialog.cpp */
1312
1313 // English
1314 folderNames[0][KFolderTreeItem::Calendar] = TQString::fromLatin1("Calendar");
1315 folderNames[0][KFolderTreeItem::Tasks] = TQString::fromLatin1("Tasks");
1316 folderNames[0][KFolderTreeItem::Journals] = TQString::fromLatin1("Journal");
1317 folderNames[0][KFolderTreeItem::Contacts] = TQString::fromLatin1("Contacts");
1318 folderNames[0][KFolderTreeItem::Notes] = TQString::fromLatin1("Notes");
1319
1320 // German
1321 folderNames[1][KFolderTreeItem::Calendar] = TQString::fromLatin1("Kalender");
1322 folderNames[1][KFolderTreeItem::Tasks] = TQString::fromLatin1("Aufgaben");
1323 folderNames[1][KFolderTreeItem::Journals] = TQString::fromLatin1("Journal");
1324 folderNames[1][KFolderTreeItem::Contacts] = TQString::fromLatin1("Kontakte");
1325 folderNames[1][KFolderTreeItem::Notes] = TQString::fromLatin1("Notizen");
1326
1327 // French
1328 folderNames[2][KFolderTreeItem::Calendar] = TQString::fromLatin1("Calendrier");
1329 // Tasks = Tâches (â == 0xE2 in latin1)
1330 folderNames[2][KFolderTreeItem::Tasks] = TQString::fromLatin1("T\342ches");
1331 folderNames[2][KFolderTreeItem::Journals] = TQString::fromLatin1("Journal");
1332 folderNames[2][KFolderTreeItem::Contacts] = TQString::fromLatin1("Contacts");
1333 folderNames[2][KFolderTreeItem::Notes] = TQString::fromLatin1("Notes");
1334
1335 // Dutch
1336 folderNames[3][KFolderTreeItem::Calendar] = TQString::fromLatin1("Agenda");
1337 folderNames[3][KFolderTreeItem::Tasks] = TQString::fromLatin1("Taken");
1338 folderNames[3][KFolderTreeItem::Journals] = TQString::fromLatin1("Logboek");
1339 folderNames[3][KFolderTreeItem::Contacts] = TQString::fromLatin1("Contactpersonen");
1340 folderNames[3][KFolderTreeItem::Notes] = TQString::fromLatin1("Notities");
1341 }
1342
1343 if( language < 0 || language > 3 ) {
1344 return folderNames[mFolderLanguage][type];
1345 }
1346 else {
1347 return folderNames[language][type];
1348 }
1349}
1350
1351
1352// Find message matching a given UID
1354{
1355 if( !folder || !mUIDToSerNum.contains( uid ) ) return 0;
1356 int i;
1357 KMFolder *aFolder;
1358 KMMsgDict::instance()->getLocation( mUIDToSerNum[uid], &aFolder, &i );
1359 Q_ASSERT( aFolder == folder );
1360 return folder->getMsg( i );
1361}
1362
1363// Find message matching a given serial number
1365{
1366 if( !folder ) return 0;
1367
1368 KMMessage *message = 0;
1369 KMFolder* aFolder = 0;
1370 int index;
1371 KMMsgDict::instance()->getLocation( serNum, &aFolder, &index );
1372
1373 if( aFolder && aFolder != folder ) {
1374 kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) found it in folder " << aFolder->location() << ", expected " << folder->location() << endl;
1375 } else {
1376 if( aFolder )
1377 message = aFolder->getMsg( index );
1378 if (!message)
1379 kdWarning(5006) << "findMessageBySerNum( " << serNum << " ) invalid serial number\n" << endl;
1380 }
1381 return message;
1382}
1383
1385{
1386 if( !msg ) return;
1387 // Commands are now delayed; can't use that anymore, we need immediate deletion
1388 //( new KMDeleteMsgCommand( msg->parent(), msg ) )->start();
1389 KMFolder *srcFolder = msg->parent();
1390 int idx = srcFolder->find(msg);
1391 assert(idx != -1);
1392 // kill existing jobs since we are about to delete the message
1393 srcFolder->ignoreJobsForMessage( msg );
1394 if ( !msg->transferInProgress() ) {
1395 srcFolder->removeMsg(idx);
1396 delete msg;
1397 } else {
1398 kdDebug(5006) << k_funcinfo << "Message cannot be deleted now because it is currently in use " << msg << endl;
1399 msg->deleteWhenUnused();
1400 }
1401 addFolderChange( srcFolder, Contents );
1402}
1403
1405 KMail::FolderContentsType contentsType )
1406{
1407 if ( !mUseResourceIMAP )
1408 return;
1409// kdDebug(5006) << "folderContentsTypeChanged( " << folder->name()
1410// << ", " << contentsType << ")\n";
1411
1412 // The builtins can't change type
1413 if ( isStandardResourceFolder( folder ) )
1414 return;
1415
1416 // Check if already know that 'extra folder'
1417 const TQString location = folder->location();
1418 ExtraFolder* ef = mExtraFolders.find( location );
1419 if ( ef && ef->folder ) {
1420 // Notify that the old folder resource is no longer available
1421 subresourceDeleted(folderContentsType( folder->storage()->contentsType() ), location );
1422
1423 if ( contentsType == KMail::ContentsTypeMail ) {
1424 // Delete the old entry, stop listening and stop here
1425 mExtraFolders.remove( location );
1426 folder->disconnect( this );
1427 return;
1428 }
1429 // So the type changed to another groupware type, ok.
1430 } else {
1431 if ( ef && !ef->folder ) // deleted folder, clean up
1432 mExtraFolders.remove( location );
1433 if ( contentsType == KMail::ContentsTypeMail )
1434 return;
1435
1436 //kdDebug(5006) << "registering " << location << " as extra folder" << endl;
1437 // Make a new entry for the list
1438 ef = new ExtraFolder( folder );
1439 mExtraFolders.insert( location, ef );
1440
1441 FolderInfo info = readFolderInfo( folder );
1442 mFolderInfoMap.insert( folder, info );
1443
1444 // Adjust the folder names of all foo.default folders.
1445 // German users will get Kalender as the name of all default Calendar folders,
1446 // including their own, so that the default calendar folder of their Japanese
1447 // coworker appears as /user/hirohito/Kalender, although Hirohito sees his folder
1448 // in Japanese. On the server the folders are always in English.
1449 if ( folder->folderType() == KMFolderTypeCachedImap ) {
1450 TQString annotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
1451 kdDebug(5006) << "folderContentsTypeChanged: " << folder->name() << " has annotation " << annotation << endl;
1452 if ( annotation == TQString( s_folderContentsType[contentsType].annotation ) + ".default" )
1453 folder->setLabel( localizedDefaultFolderName( contentsType ) );
1454 }
1455
1456 connectFolder( folder );
1457 }
1458 // Tell about the new resource
1459 subresourceAdded( folderContentsType( contentsType ), location, subresourceLabelForPresentation(folder),
1460 folder->isWritable(), folderIsAlarmRelevant( folder ) );
1461}
1462
1463KMFolder* KMailICalIfaceImpl::extraFolder( const TQString& type,
1464 const TQString& folder )
1465{
1466 // If an extra folder exists that matches the type and folder location,
1467 // use that
1468 int t = folderContentsType( type );
1469 if ( t < 1 || t > 5 )
1470 return 0;
1471
1472 ExtraFolder* ef = mExtraFolders.find( folder );
1473 if ( ef && ef->folder && ef->folder->storage()->contentsType() == t )
1474 return ef->folder;
1475
1476 return 0;
1477}
1478
1479KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::storageFormat( KMFolder* folder ) const
1480{
1481 FolderInfoMap::ConstIterator it = mFolderInfoMap.find( folder );
1482 if ( it != mFolderInfoMap.end() )
1483 return (*it).mStorageFormat;
1484 return globalStorageFormat();
1485}
1486
1487void KMailICalIfaceImpl::setStorageFormat( KMFolder* folder, StorageFormat format )
1488{
1489 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
1490 if ( it != mFolderInfoMap.end() ) {
1491 (*it).mStorageFormat = format;
1492 } else {
1493 FolderInfo info( format, NoChange );
1494 mFolderInfoMap.insert( folder, info );
1495 }
1496 TDEConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
1497 configGroup.writeEntry( folder->idString() + "-storageFormat",
1498 format == StorageXML ? "xml" : "icalvcard" );
1499}
1500
1501void KMailICalIfaceImpl::addFolderChange( KMFolder* folder, FolderChanges changes )
1502{
1503 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
1504 if ( it != mFolderInfoMap.end() ) {
1505 (*it).mChanges = static_cast<FolderChanges>( (*it).mChanges | changes );
1506 } else { // Otherwise, well, it's a folder we don't care about.
1507 kdDebug(5006) << "addFolderChange: nothing known about folder " << folder->location() << endl;
1508 }
1509 TDEConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
1510 configGroup.writeEntry( folder->idString() + "-changes", (*it).mChanges );
1511}
1512
1513KMailICalIfaceImpl::FolderInfo KMailICalIfaceImpl::readFolderInfo( const KMFolder * const folder ) const
1514{
1515 TDEConfigGroup configGroup( kmkernel->config(), "GroupwareFolderInfo" );
1516 TQString str = configGroup.readEntry( folder->idString() + "-storageFormat", "unset" );
1517 FolderInfo info;
1518 if ( str == "unset" ) {
1519 info.mStorageFormat = globalStorageFormat();
1520 configGroup.writeEntry( folder->idString() + "-storageFormat",
1521 info.mStorageFormat == StorageXML ? "xml" : "icalvcard" );
1522 } else {
1523 info.mStorageFormat = ( str == "xml" ) ? StorageXML : StorageIcalVcard;
1524 }
1525 info.mChanges = (FolderChanges) configGroup.readNumEntry( folder->idString() + "-changes" );
1526 return info;
1527}
1528
1529
1530void KMailICalIfaceImpl::folderSynced( KMFolder* folder, const KURL& folderURL )
1531{
1532 FolderInfoMap::Iterator it = mFolderInfoMap.find( folder );
1533 if ( it != mFolderInfoMap.end() && (*it).mChanges ) {
1534 handleFolderSynced( folder, folderURL, (*it).mChanges );
1535 (*it).mChanges = NoChange;
1536 }
1537}
1538
1539void KMailICalIfaceImpl::handleFolderSynced( KMFolder* folder,
1540 const KURL& folderURL,
1541 int _changes )
1542{
1543 // This is done here instead of in the resource, because
1544 // there could be 0, 1, or N kolab resources at this point.
1545 // We can hack the N case, but not the 0 case.
1546 // So the idea of a DCOP signal for this wouldn't work.
1547 if ( ( _changes & KMailICalIface::Contents ) ||
1548 ( _changes & KMailICalIface::ACL ) ) {
1549 if ( storageFormat( folder ) == StorageXML && folder->storage()->contentsType() == KMail::ContentsTypeCalendar )
1550 triggerKolabFreeBusy( folderURL );
1551 }
1552}
1553
1554void KMailICalIfaceImpl::folderDeletedOnServer( const KURL& folderURL )
1555{
1556 triggerKolabFreeBusy( folderURL );
1557}
1558
1559void KMailICalIfaceImpl::triggerKolabFreeBusy( const KURL& folderURL )
1560{
1561 /* Steffen said: you must issue an authenticated HTTP GET request to
1562 https://kolabserver/freebusy/trigger/user@domain/Folder/NestedFolder.pfb
1563 (replace .pfb with .xpfb for extended fb lists). */
1564 KURL httpURL( folderURL );
1565 // Keep username ("user@domain"), pass, and host from the imap url
1566 httpURL.setProtocol( "https" );
1567 httpURL.setPort( 0 ); // remove imap port
1568
1569 // IMAP path is either /INBOX/<path> or /user/someone/<path>
1570 TQString path = folderURL.path( -1 );
1571 Q_ASSERT( path.startsWith( "/" ) );
1572 int secondSlash = path.find( '/', 1 );
1573 if ( secondSlash == -1 ) {
1574 kdWarning() << "KCal::ResourceKolab::fromKMailFolderSynced path is too short: " << path << endl;
1575 return;
1576 }
1577 if ( path.startsWith( "/INBOX/", false ) ) {
1578 // If INBOX, replace it with the username (which is user@domain)
1579 path = path.mid( secondSlash );
1580 path.prepend( folderURL.user() );
1581 } else {
1582 // If user, just remove it. So we keep the IMAP-returned username.
1583 // This assumes it's a known user on the same domain.
1584 path = path.mid( secondSlash );
1585 }
1586
1587 httpURL.setPath( "/freebusy/trigger/" + path + ".pfb" );
1588 httpURL.setQuery( TQString() );
1589 // Ensure that we encode everything with UTF8
1590 httpURL = KURL( httpURL.url(0,106), 106 );
1591 kdDebug() << "Triggering PFB update for " << folderURL << " : getting " << httpURL << endl;
1592 // "Fire and forget". No need for error handling, nor for explicit deletion.
1593 // Maybe we should try to prevent launching it if it's already running (for this URL) though.
1594 /*TDEIO::Job* job =*/ TDEIO::get( httpURL, false, false /*no progress info*/ );
1595}
1596
1597void KMailICalIfaceImpl::slotFolderPropertiesChanged( KMFolder* folder )
1598{
1599 if ( isResourceFolder( folder ) ) {
1600 const TQString location = folder->location();
1601 const TQString contentsTypeStr = folderContentsType( folder->storage()->contentsType() );
1602 subresourceDeleted( contentsTypeStr, location );
1603
1604 subresourceAdded( contentsTypeStr, location, subresourceLabelForPresentation( folder ),
1605 folder->isWritable(), folderIsAlarmRelevant( folder ) );
1606 }
1607}
1608
1609// Must only be connected to a signal from KMFolder!
1610void KMailICalIfaceImpl::slotFolderRenamed()
1611{
1612 const KMFolder* folder = static_cast<const KMFolder *>( sender() );
1613 slotFolderPropertiesChanged( const_cast<KMFolder*>( folder ) );
1614}
1615
1616void KMailICalIfaceImpl::slotFolderLocationChanged( const TQString &oldLocation,
1617 const TQString &newLocation )
1618{
1619 KMFolder *folder = findResourceFolder( oldLocation );
1620 ExtraFolder* ef = mExtraFolders.find( oldLocation );
1621 if ( ef ) {
1622 // reuse the ExtraFolder entry, but adjust the key
1623 mExtraFolders.setAutoDelete( false );
1624 mExtraFolders.remove( oldLocation );
1625 mExtraFolders.setAutoDelete( true );
1626 mExtraFolders.insert( newLocation, ef );
1627 }
1628 if ( folder )
1629 subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), oldLocation );
1630
1631}
1632
1633KMFolder* KMailICalIfaceImpl::findResourceFolder( const TQString& resource )
1634{
1635 // Try the standard folders
1636 if( mCalendar && mCalendar->location() == resource )
1637 return mCalendar;
1638 if ( mContacts && mContacts->location() == resource )
1639 return mContacts;
1640 if ( mNotes && mNotes->location() == resource )
1641 return mNotes;
1642 if ( mTasks && mTasks->location() == resource )
1643 return mTasks;
1644 if ( mJournals && mJournals->location() == resource )
1645 return mJournals;
1646
1647 // No luck. Try the extrafolders
1648 ExtraFolder* ef = mExtraFolders.find( resource );
1649 if ( ef )
1650 return ef->folder;
1651
1652 // No luck at all
1653 return 0;
1654}
1655
1656void KMailICalIfaceImpl::changeResourceUIName( const TQString &folderPath, const TQString &newName )
1657{
1658 kdDebug() << "Folder path " << folderPath << endl;
1659 KMFolder *f = findResourceFolder( folderPath );
1660 if ( f ) {
1661 KMailICalIfaceImpl::getResourceMap()->insert( folderPath, newName );
1662 kmkernel->folderMgr()->renameFolder( f, newName );
1663 TDEConfigGroup configGroup( kmkernel->config(), "Resource UINames" );
1664 configGroup.writeEntry( folderPath, newName );
1665 }
1666}
1667
1668// Builds a folder list from the dimap and the local folder list.
1669static void createFolderList( TQStringList &folderNames, TQValueList<TQGuardedPtr<KMFolder> > &folderList )
1670{
1671 TQStringList dimapFolderNames;
1672 TQStringList localFolderNames;
1673 TQValueList<TQGuardedPtr<KMFolder> > dimapFolderList;
1674 TQValueList<TQGuardedPtr<KMFolder> > localFolderList;
1675 kmkernel->dimapFolderMgr()->createFolderList( &dimapFolderNames, &dimapFolderList );
1676 kmkernel->folderMgr()->createFolderList( &localFolderNames, &localFolderList );
1677 folderNames += dimapFolderNames;
1678 folderNames += localFolderNames;
1679 folderList += dimapFolderList;
1680 folderList += localFolderList;
1681}
1682
1683/****************************
1684 * The config stuff
1685 */
1686
1687void KMailICalIfaceImpl::readConfig()
1688{
1689 bool enabled = GlobalSettings::self()->theIMAPResourceEnabled() &&
1690 ( GlobalSettings::self()->theIMAPResourceAccount() != 0 );
1691
1692 if( !enabled ) {
1693 if( mUseResourceIMAP == true ) {
1694 // Shutting down
1695 mUseResourceIMAP = false;
1696 cleanup();
1697 reloadFolderTree();
1698 }
1699 return;
1700 }
1701 mUseResourceIMAP = enabled;
1702
1703 // Read remaining options
1704 const bool hideFolders = GlobalSettings::self()->hideGroupwareFolders();
1705 TQString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
1706
1707 // Find the folder parent
1708 KMFolderDir* folderParentDir;
1709 KMFolderType folderType;
1710 KMFolder* folderParent = kmkernel->findFolderById( parentName );
1711 if( folderParent == 0 ) {
1712 // Parent folder not found. It was probably deleted. The user will have to
1713 // configure things again.
1714 kdDebug(5006) << "Groupware folder " << parentName << " not found. Groupware functionality disabled" << endl;
1715 // Or maybe the inbox simply wasn't created on the first startup
1716 KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
1717 Q_ASSERT( account );
1718 if ( account ) {
1719 // just in case we were connected already
1720 disconnect( account, TQ_SIGNAL( finishedCheck( bool, CheckStatus ) ),
1721 this, TQ_SLOT( slotCheckDone() ) );
1722 connect( account, TQ_SIGNAL( finishedCheck( bool, CheckStatus ) ),
1723 this, TQ_SLOT( slotCheckDone() ) );
1724 }
1725 mUseResourceIMAP = false;
1726 // We can't really call cleanup(), if those folders were completely deleted.
1727 mCalendar = 0;
1728 mTasks = 0;
1729 mJournals = 0;
1730 mContacts = 0;
1731 mNotes = 0;
1732 return;
1733 } else {
1734 folderParentDir = folderParent->createChildFolder();
1735 folderType = folderParent->folderType();
1736 }
1737
1738 KMAcctCachedImap::GroupwareType groupwareType = dynamic_cast<KMFolderCachedImap *>( folderParent->storage() )->account()->groupwareType();
1739
1740 if ( groupwareType == KMAcctCachedImap::GroupwareKolab ) {
1741 // Make sure the folder parent has the subdirs
1742 // Globally there are 3 cases: nothing found, some stuff found by type/name heuristics, or everything found OK
1743 bool noneFound = true;
1744 bool mustFix = false; // true when at least one was found by heuristics
1745 TQValueVector<StandardFolderSearchResult> results( KMail::ContentsTypeLast + 1 );
1746 for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
1747 if ( i != KMail::ContentsTypeMail ) {
1748 results[i] = findStandardResourceFolder( folderParentDir, static_cast<KMail::FolderContentsType>(i) );
1749 if ( results[i].found == StandardFolderSearchResult::FoundAndStandard )
1750 noneFound = false;
1751 else if ( results[i].found == StandardFolderSearchResult::FoundByType ||
1752 results[i].found == StandardFolderSearchResult::FoundByName ) {
1753 mustFix = true;
1754 noneFound = false;
1755 } else // NotFound
1756 mustFix = true;
1757 }
1758 }
1759
1760 // Check if something changed
1761 if( mUseResourceIMAP && !noneFound && !mustFix && mFolderParentDir == folderParentDir
1762 && mFolderType == folderType ) {
1763 // Nothing changed
1764 if ( hideFolders != mHideFolders ) {
1765 // Well, the folder hiding has changed
1766 mHideFolders = hideFolders;
1767 reloadFolderTree();
1768 }
1769 return;
1770 }
1771
1772 if( noneFound || mustFix ) {
1773 TQString msg;
1774 TQString parentFolderName = folderParent != 0 ? folderParent->name() : folderParentDir->name();
1775 if ( noneFound ) {
1776 // No subfolder was found, so ask if we can make them
1777 msg = i18n("KMail will now create the required groupware folders"
1778 " as subfolders of %1; if you do not want this, cancel"
1779 " and the IMAP resource will be disabled").arg(parentFolderName);
1780 } else {
1781 // Some subfolders were found, be more precise
1782 TQString operations = "<ul>";
1783 for ( int i = 0; i < KMail::ContentsTypeLast+1; ++i ) {
1784 if ( i != KMail::ContentsTypeMail ) {
1785 TQString typeName = localizedDefaultFolderName( static_cast<KMail::FolderContentsType>( i ) );
1786 if ( results[i].found == StandardFolderSearchResult::NotFound )
1787 operations += "<li>" + i18n( "%1: no folder found. It will be created." ).arg( typeName ) + "</li>";
1788 else if ( results[i].found == StandardFolderSearchResult::FoundByType || results[i].found == StandardFolderSearchResult::FoundByName )
1789 operations += "<li>" + i18n( "%1: found folder %2. It will be set as the main groupware folder." ).
1790 arg( typeName ).arg( results[i].folder->label() ) + "</li>";
1791 }
1792 }
1793 operations += "</ul>";
1794
1795 msg = i18n("<qt>KMail found the following groupware folders in %1 and needs to perform the following operations: %2"
1796 "<br>If you do not want this, cancel"
1797 " and the IMAP resource will be disabled").arg(parentFolderName, operations);
1798
1799 }
1800
1801 if( KMessageBox::questionYesNo( 0, msg,
1802 i18n("Standard Groupware Folders"), KStdGuiItem::cont(), KStdGuiItem::cancel() ) == KMessageBox::No ) {
1803
1804 GlobalSettings::self()->setTheIMAPResourceEnabled( false );
1805 mUseResourceIMAP = false;
1806 mFolderParentDir = 0;
1807 mFolderParent = 0;
1808 reloadFolderTree();
1809 return;
1810 }
1811 }
1812
1813 // Make the new settings work
1814 mUseResourceIMAP = true;
1815 mFolderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
1816 if( mFolderLanguage > 3 ) mFolderLanguage = 0;
1817 mFolderParentDir = folderParentDir;
1818 mFolderParent = folderParent;
1819 mFolderType = folderType;
1820 mHideFolders = hideFolders;
1821
1822 // Close the previous folders
1823 cleanup();
1824
1825 // Set the new folders
1826 mCalendar = initFolder( KMail::ContentsTypeCalendar );
1827 mTasks = initFolder( KMail::ContentsTypeTask );
1828 mJournals = initFolder( KMail::ContentsTypeJournal );
1829 mContacts = initFolder( KMail::ContentsTypeContact );
1830 mNotes = initFolder( KMail::ContentsTypeNote );
1831
1832 // Store final annotation (with .default) so that we won't ask again on next startup
1833 if ( mCalendar->folderType() == KMFolderTypeCachedImap )
1834 static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
1835 if ( mTasks->folderType() == KMFolderTypeCachedImap )
1836 static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
1837 if ( mJournals->folderType() == KMFolderTypeCachedImap )
1838 static_cast<KMFolderCachedImap *>( mJournals->storage() )->updateAnnotationFolderType();
1839 if ( mContacts->folderType() == KMFolderTypeCachedImap )
1840 static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
1841 if ( mNotes->folderType() == KMFolderTypeCachedImap )
1842 static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
1843
1844 //kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
1845 //kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
1846 //kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
1847
1848 // Find all extra folders
1849 TQStringList folderNames;
1850 TQValueList<TQGuardedPtr<KMFolder> > folderList;
1851 createFolderList( folderNames, folderList );
1852 for( TQValueList<TQGuardedPtr<KMFolder> >::iterator it = folderList.begin();
1853 it != folderList.end(); ++it )
1854 {
1855 FolderStorage *storage = (*it)->storage();
1856 KMFolderCachedImap* dimapStorage = dynamic_cast<KMFolderCachedImap*>( storage );
1857 if ( storage && storage->contentsType() != 0 ) {
1858 if ( dimapStorage )
1859 dimapStorage->updateAnnotationFolderType();
1860 folderContentsTypeChanged( *it, storage->contentsType() );
1861 }
1862 }
1863
1864 // If we just created them, they might have been registered as extra folders temporarily.
1865 // -> undo that.
1866 mExtraFolders.remove( mCalendar->location() );
1867 mExtraFolders.remove( mTasks->location() );
1868 mExtraFolders.remove( mJournals->location() );
1869 mExtraFolders.remove( mContacts->location() );
1870 mExtraFolders.remove( mNotes->location() );
1871
1872 subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
1873 subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
1874 subresourceAdded( folderContentsType( KMail::ContentsTypeJournal ), mJournals->location(), mJournals->label(), true, false );
1875 subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
1876 subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
1877 } else if ( groupwareType == KMAcctCachedImap::GroupwareScalix ) {
1878 // Make the new settings work
1879 mUseResourceIMAP = true;
1880 mFolderParentDir = folderParentDir;
1881 mFolderParent = folderParent;
1882 mFolderType = folderType;
1883 mHideFolders = false;
1884
1885 // Close the previous folders
1886 cleanup();
1887
1888 // Set the new folders
1889 mCalendar = initScalixFolder( KMail::ContentsTypeCalendar );
1890 mTasks = initScalixFolder( KMail::ContentsTypeTask );
1891 mJournals = 0;
1892 mContacts = initScalixFolder( KMail::ContentsTypeContact );
1893 mNotes = initScalixFolder( KMail::ContentsTypeNote );
1894
1895 // Store final annotation (with .default) so that we won't ask again on next startup
1896 if ( mCalendar->folderType() == KMFolderTypeCachedImap )
1897 static_cast<KMFolderCachedImap *>( mCalendar->storage() )->updateAnnotationFolderType();
1898 if ( mTasks->folderType() == KMFolderTypeCachedImap )
1899 static_cast<KMFolderCachedImap *>( mTasks->storage() )->updateAnnotationFolderType();
1900 if ( mContacts->folderType() == KMFolderTypeCachedImap )
1901 static_cast<KMFolderCachedImap *>( mContacts->storage() )->updateAnnotationFolderType();
1902 if ( mNotes->folderType() == KMFolderTypeCachedImap )
1903 static_cast<KMFolderCachedImap *>( mNotes->storage() )->updateAnnotationFolderType();
1904
1905 // BEGIN TILL TODO The below only uses the dimap folder manager, which
1906 // will fail for all other folder types. Adjust.
1907
1908 kdDebug(5006) << k_funcinfo << "mCalendar=" << mCalendar << " " << mCalendar->location() << endl;
1909 kdDebug(5006) << k_funcinfo << "mContacts=" << mContacts << " " << mContacts->location() << endl;
1910 kdDebug(5006) << k_funcinfo << "mNotes=" << mNotes << " " << mNotes->location() << endl;
1911
1912 // Find all extra folders
1913 TQStringList folderNames;
1914 TQValueList<TQGuardedPtr<KMFolder> > folderList;
1915 kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
1916 TQValueList<TQGuardedPtr<KMFolder> >::iterator it;
1917 for(it = folderList.begin(); it != folderList.end(); ++it)
1918 {
1919 FolderStorage *storage = (*it)->storage();
1920
1921 if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
1922 KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
1923
1924 const TQString attributes = imapFolder->folderAttributes();
1925 if ( attributes.contains( "X-FolderClass" ) ) {
1926 if ( !attributes.contains( "X-SpecialFolder" ) || (*it)->location().contains( "@" ) ) {
1927 const Scalix::FolderAttributeParser parser( attributes );
1928 if ( !parser.folderClass().isEmpty() ) {
1929 FolderContentsType type = Scalix::Utils::scalixIdToContentsType( parser.folderClass() );
1930 imapFolder->setContentsType( type );
1931 folderContentsTypeChanged( *it, type );
1932 }
1933 }
1934 }
1935 }
1936 }
1937
1938 // If we just created them, they might have been registered as extra folders temporarily.
1939 // -> undo that.
1940 mExtraFolders.remove( mCalendar->location() );
1941 mExtraFolders.remove( mTasks->location() );
1942 mExtraFolders.remove( mContacts->location() );
1943 mExtraFolders.remove( mNotes->location() );
1944
1945 // END TILL TODO
1946
1947 subresourceAdded( folderContentsType( KMail::ContentsTypeCalendar ), mCalendar->location(), mCalendar->label(), true, true );
1948 subresourceAdded( folderContentsType( KMail::ContentsTypeTask ), mTasks->location(), mTasks->label(), true, true );
1949 subresourceAdded( folderContentsType( KMail::ContentsTypeContact ), mContacts->location(), mContacts->label(), true, false );
1950 subresourceAdded( folderContentsType( KMail::ContentsTypeNote ), mNotes->location(), mNotes->label(), true, false );
1951 }
1952
1953 TDEConfig *config = kmkernel->config();
1954 config->setGroup("Resource UINames");
1955 *KMailICalIfaceImpl::mSubResourceUINamesMap = config->entryMap( "Resource UINames" );
1956
1957 reloadFolderTree();
1958}
1959
1960void KMailICalIfaceImpl::slotCheckDone()
1961{
1962 TQString parentName = GlobalSettings::self()->theIMAPResourceFolderParent();
1963 KMFolder* folderParent = kmkernel->findFolderById( parentName );
1964 //kdDebug(5006) << k_funcinfo << " folderParent=" << folderParent << endl;
1965 if ( folderParent ) // cool it exists now
1966 {
1967 KMAccount* account = kmkernel->acctMgr()->find( GlobalSettings::self()->theIMAPResourceAccount() );
1968 if ( account )
1969 disconnect( account, TQ_SIGNAL( finishedCheck( bool, CheckStatus ) ),
1970 this, TQ_SLOT( slotCheckDone() ) );
1971 readConfig();
1972 }
1973}
1974
1975KMFolder* KMailICalIfaceImpl::initFolder( KMail::FolderContentsType contentsType )
1976{
1977 // Figure out what type of folder this is supposed to be
1978 KMFolderType type = mFolderType;
1979 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
1980
1981 KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
1982 //kdDebug(5006) << "KMailICalIfaceImpl::initFolder " << folderName( itemType ) << endl;
1983
1984 // Find the folder
1985 StandardFolderSearchResult result = findStandardResourceFolder( mFolderParentDir, contentsType );
1986
1987 // deal with multiple default groupware folders
1988 if ( result.folders.count() > 1 && result.found == StandardFolderSearchResult::FoundAndStandard ) {
1989 TQStringList labels;
1990 for ( TQValueList<KMFolder*>::ConstIterator it = result.folders.begin(); it != result.folders.end(); ++it )
1991 labels << (*it)->prettyURL();
1992 const TQString selected = KInputDialog::getItem( i18n("Default folder"),
1993 i18n("There are multiple %1 default folders, please choose one:")
1994 .arg( localizedDefaultFolderName( contentsType ) ), labels );
1995 if ( !selected.isEmpty() )
1996 result.folder = result.folders[ labels.findIndex( selected ) ];
1997 }
1998
1999 KMFolder* folder = result.folder;
2000
2001 if ( !folder ) {
2002 // The folder isn't there yet - create it
2003 folder =
2004 mFolderParentDir->createFolder( localizedDefaultFolderName( contentsType ), false, type );
2005 if( mFolderType == KMFolderTypeImap ) {
2006 KMFolderImap* parentFolder = static_cast<KMFolderImap*>( mFolderParent->storage() );
2007 parentFolder->createFolder( localizedDefaultFolderName( contentsType ) );
2008 static_cast<KMFolderImap*>( folder->storage() )->setAccount( parentFolder->account() );
2009 }
2010 // Groupware folder created, use the global setting for storage format
2011 setStorageFormat( folder, globalStorageFormat() );
2012 } else {
2013 FolderInfo info = readFolderInfo( folder );
2014 mFolderInfoMap.insert( folder, info );
2015 //kdDebug(5006) << "Found existing folder type " << itemType << " : " << folder->location() << endl;
2016 }
2017
2018 if( folder->canAccess() != 0 ) {
2019 KMessageBox::sorry(0, i18n("You do not have read/write permission to your %1 folder.")
2020 .arg( folderName( itemType ) ) );
2021 return 0;
2022 }
2023 folder->storage()->setContentsType( contentsType );
2024 folder->setSystemFolder( true );
2025 folder->storage()->writeConfig();
2026 folder->open("ifacefolder");
2027 connectFolder( folder );
2028 return folder;
2029}
2030
2031KMFolder* KMailICalIfaceImpl::initScalixFolder( KMail::FolderContentsType contentsType )
2032{
2033 // Figure out what type of folder this is supposed to be
2034 KMFolderType type = mFolderType;
2035 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
2036
2037 KMFolder* folder = 0;
2038
2039 // Find all extra folders
2040 TQStringList folderNames;
2041 TQValueList<TQGuardedPtr<KMFolder> > folderList;
2042 Q_ASSERT( kmkernel );
2043 Q_ASSERT( kmkernel->dimapFolderMgr() );
2044 kmkernel->dimapFolderMgr()->createFolderList(&folderNames, &folderList);
2045 TQValueList<TQGuardedPtr<KMFolder> >::iterator it = folderList.begin();
2046 for(; it != folderList.end(); ++it)
2047 {
2048 FolderStorage *storage = (*it)->storage();
2049
2050 if ( (*it)->folderType() == KMFolderTypeCachedImap ) {
2051 KMFolderCachedImap *imapFolder = static_cast<KMFolderCachedImap*>( storage );
2052
2053 const TQString attributes = imapFolder->folderAttributes();
2054 if ( attributes.contains( "X-SpecialFolder" ) ) {
2055 const Scalix::FolderAttributeParser parser( attributes );
2056 if ( contentsType == Scalix::Utils::scalixIdToContentsType( parser.folderClass() ) ) {
2057 folder = *it;
2058 break;
2059 }
2060 }
2061 }
2062 }
2063
2064 if ( !folder ) {
2065 return 0;
2066 } else {
2067 FolderInfo info = readFolderInfo( folder );
2068 mFolderInfoMap.insert( folder, info );
2069 //kdDebug(5006) << "Found existing folder type " << itemType << " : " << folder->location() << endl;
2070 }
2071
2072 if( folder->canAccess() != 0 ) {
2073 KMessageBox::sorry(0, i18n("You do not have read/write permission to your folder.") );
2074 return 0;
2075 }
2076 folder->storage()->setContentsType( contentsType );
2077 folder->setSystemFolder( true );
2078 folder->storage()->writeConfig();
2079 folder->open( "scalixfolder" );
2080 connectFolder( folder );
2081 return folder;
2082}
2083
2084void KMailICalIfaceImpl::connectFolder( KMFolder* folder )
2085{
2086 // avoid multiple connections
2087 disconnect( folder, TQ_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ),
2088 this, TQ_SLOT( slotIncidenceAdded( KMFolder*, TQ_UINT32 ) ) );
2089 disconnect( folder, TQ_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ),
2090 this, TQ_SLOT( slotIncidenceDeleted( KMFolder*, TQ_UINT32 ) ) );
2091 disconnect( folder, TQ_SIGNAL( expunged( KMFolder* ) ),
2092 this, TQ_SLOT( slotRefreshFolder( KMFolder* ) ) );
2093 disconnect( folder->storage(), TQ_SIGNAL( readOnlyChanged( KMFolder* ) ),
2094 this, TQ_SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
2095 disconnect( folder, TQ_SIGNAL( nameChanged() ),
2096 this, TQ_SLOT( slotFolderRenamed() ) );
2097 disconnect( folder->storage(), TQ_SIGNAL( locationChanged( const TQString&, const TQString&) ),
2098 this, TQ_SLOT( slotFolderLocationChanged( const TQString&, const TQString&) ) );
2099
2100 // Setup the signals to listen for changes
2101 connect( folder, TQ_SIGNAL( msgAdded( KMFolder*, TQ_UINT32 ) ),
2102 this, TQ_SLOT( slotIncidenceAdded( KMFolder*, TQ_UINT32 ) ) );
2103 connect( folder, TQ_SIGNAL( msgRemoved( KMFolder*, TQ_UINT32 ) ),
2104 this, TQ_SLOT( slotIncidenceDeleted( KMFolder*, TQ_UINT32 ) ) );
2105 connect( folder, TQ_SIGNAL( expunged( KMFolder* ) ),
2106 this, TQ_SLOT( slotRefreshFolder( KMFolder* ) ) );
2107 connect( folder->storage(), TQ_SIGNAL( readOnlyChanged( KMFolder* ) ),
2108 this, TQ_SLOT( slotFolderPropertiesChanged( KMFolder* ) ) );
2109 connect( folder, TQ_SIGNAL( nameChanged() ),
2110 this, TQ_SLOT( slotFolderRenamed() ) );
2111 connect( folder->storage(), TQ_SIGNAL( locationChanged( const TQString&, const TQString&) ),
2112 this, TQ_SLOT( slotFolderLocationChanged( const TQString&, const TQString&) ) );
2113
2114}
2115
2116static void cleanupFolder( KMFolder* folder, KMailICalIfaceImpl* _this )
2117{
2118 if( folder ) {
2119 folder->setSystemFolder( false );
2120 folder->disconnect( _this );
2121 folder->close("ifacefolder");
2122 }
2123}
2124
2126{
2127 cleanupFolder( mContacts, this );
2128 cleanupFolder( mCalendar, this );
2129 cleanupFolder( mNotes, this );
2130 cleanupFolder( mTasks, this );
2131 cleanupFolder( mJournals, this );
2132
2133 mContacts = mCalendar = mNotes = mTasks = mJournals = 0;
2134}
2135
2136TQString KMailICalIfaceImpl::folderPixmap( KFolderTreeItem::Type type ) const
2137{
2138 if( !mUseResourceIMAP )
2139 return TQString();
2140
2141 if( type == KFolderTreeItem::Contacts )
2142 return TQString::fromLatin1( "kmgroupware_folder_contacts" );
2143 else if( type == KFolderTreeItem::Calendar )
2144 return TQString::fromLatin1( "kmgroupware_folder_calendar" );
2145 else if( type == KFolderTreeItem::Notes )
2146 return TQString::fromLatin1( "kmgroupware_folder_notes" );
2147 else if( type == KFolderTreeItem::Tasks )
2148 return TQString::fromLatin1( "kmgroupware_folder_tasks" );
2149 else if( type == KFolderTreeItem::Journals )
2150 return TQString::fromLatin1( "kmgroupware_folder_journals" );
2151
2152 return TQString();
2153}
2154
2155static void reloadFolderTree()
2156{
2157 // Make the folder tree show the icons or not
2158 kmkernel->folderMgr()->contentsChanged();
2159}
2160
2161// This is a very light-weight and fast 'parser' to retrieve
2162// a data entry from a vCal taking continuation lines
2163// into account
2164static void vPartMicroParser( const TQString& str, TQString& s )
2165{
2166 TQString line;
2167 uint len = str.length();
2168
2169 for( uint i=0; i<len; ++i){
2170 if( str[i] == '\r' || str[i] == '\n' ){
2171 if( str[i] == '\r' )
2172 ++i;
2173 if( i+1 < len && str[i+1] == ' ' ){
2174 // found a continuation line, skip it's leading blanc
2175 ++i;
2176 }else{
2177 // found a logical line end, process the line
2178 if( line.startsWith( s ) ) {
2179 s = line.mid( s.length() + 1 );
2180 return;
2181 }
2182 line = "";
2183 }
2184 } else {
2185 line += str[i];
2186 }
2187 }
2188
2189 // Not found. Clear it
2190 s.truncate(0);
2191}
2192
2193// Returns the first child folder having the given annotation
2194static TQValueList<KMFolder*> findFolderByAnnotation( KMFolderDir* folderParentDir, const TQString& annotation )
2195{
2196 TQValueList<KMFolder*> rv;
2197 TQPtrListIterator<KMFolderNode> it( *folderParentDir );
2198 for ( ; it.current(); ++it ) {
2199 if ( !it.current()->isDir() ) {
2200 KMFolder* folder = static_cast<KMFolder *>( it.current() );
2201 if ( folder->folderType() == KMFolderTypeCachedImap ) {
2202 TQString folderAnnotation = static_cast<KMFolderCachedImap*>( folder->storage() )->annotationFolderType();
2203 //kdDebug(5006) << "findStandardResourceFolder: " << folder->name() << " has annotation " << folderAnnotation << endl;
2204 if ( folderAnnotation == annotation )
2205 rv.append( folder );
2206 }
2207 }
2208 }
2209 return rv;
2210}
2211
2212KMailICalIfaceImpl::StandardFolderSearchResult KMailICalIfaceImpl::findStandardResourceFolder( KMFolderDir* folderParentDir, KMail::FolderContentsType contentsType )
2213{
2214 if ( GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML )
2215 {
2216 // Look for a folder with an annotation like "event.default"
2217 TQValueList<KMFolder*> folders = findFolderByAnnotation( folderParentDir, TQString( s_folderContentsType[contentsType].annotation ) + ".default" );
2218 if ( !folders.isEmpty() )
2219 return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundAndStandard );
2220
2221 // Fallback: look for a folder with an annotation like "event"
2222 folders = findFolderByAnnotation( folderParentDir, TQString( s_folderContentsType[contentsType].annotation ) );
2223 if ( !folders.isEmpty() )
2224 return StandardFolderSearchResult( folders, StandardFolderSearchResult::FoundByType );
2225
2226 // Fallback: look for the folder by name (we'll need to change its type)
2227 KMFolderNode* node = folderParentDir->hasNamedFolder( localizedDefaultFolderName( contentsType ) );
2228 if ( node && !node->isDir() )
2229 return StandardFolderSearchResult( static_cast<KMFolder *>( node ), StandardFolderSearchResult::FoundByName );
2230
2231 kdDebug(5006) << "findStandardResourceFolder: found no resource folder for " << s_folderContentsType[contentsType].annotation << endl;
2232 return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
2233 }
2234 else // icalvcard: look up standard resource folders by name
2235 {
2236 KFolderTreeItem::Type itemType = s_folderContentsType[contentsType].treeItemType;
2237 unsigned int folderLanguage = GlobalSettings::self()->theIMAPResourceFolderLanguage();
2238 if( folderLanguage > 3 ) folderLanguage = 0;
2239 KMFolderNode* node = folderParentDir->hasNamedFolder( folderName( itemType, folderLanguage ) );
2240 if ( !node || node->isDir() )
2241 return StandardFolderSearchResult( 0, StandardFolderSearchResult::NotFound );
2242 return StandardFolderSearchResult( static_cast<KMFolder*>( node ), StandardFolderSearchResult::FoundAndStandard );
2243 }
2244}
2245
2246/* We treat all folders as relevant wrt alarms for which we have Administer
2247 * rights or for which the "Incidences relevant for everyone" annotation has
2248 * been set. It can be reasonably assumed that those are "ours". All local folders
2249 * must be ours anyhow. */
2250bool KMailICalIfaceImpl::folderIsAlarmRelevant( const KMFolder *folder )
2251{
2252 bool administerRights = true;
2253 bool relevantForOwner = true;
2254 bool relevantForEveryone = false;
2255 if ( folder->folderType() == KMFolderTypeImap ) {
2256 const KMFolderImap *imapFolder = static_cast<const KMFolderImap*>( folder->storage() );
2257 administerRights =
2258 imapFolder->userRightsState() != KMail::ACLJobs::Ok ||
2259 imapFolder->userRights() & KMail::ACLJobs::Administer;
2260 }
2261 if ( folder->folderType() == KMFolderTypeCachedImap ) {
2262 const KMFolderCachedImap *dimapFolder = static_cast<const KMFolderCachedImap*>( folder->storage() );
2263 administerRights =
2264 dimapFolder->userRightsState() != KMail::ACLJobs::Ok ||
2265 dimapFolder->userRights() & KMail::ACLJobs::Administer;
2266 relevantForOwner = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor () == KMFolderCachedImap::IncForAdmins );
2267 relevantForEveryone = !dimapFolder->alarmsBlocked() && ( dimapFolder->incidencesFor() == KMFolderCachedImap::IncForReaders );
2268 }
2269#if 0
2270 kdDebug(5006) << k_funcinfo << endl;
2271 kdDebug(5006) << "Folder: " << folder->label() << " has administer rights: " << administerRights << endl;
2272 kdDebug(5006) << "and is relevant for owner: " << relevantForOwner << endl;
2273 kdDebug(5006) << "and relevant for everyone: " << relevantForEveryone << endl;
2274#endif
2275 return ( administerRights && relevantForOwner ) || relevantForEveryone;
2276}
2277
2278void KMailICalIfaceImpl::setResourceQuiet(bool q)
2279{
2280 mResourceQuiet = q;
2281}
2282
2283bool KMailICalIfaceImpl::isResourceQuiet() const
2284{
2285 return mResourceQuiet;
2286}
2287
2288
2289bool KMailICalIfaceImpl::addSubresource( const TQString& resource,
2290 const TQString& parent,
2291 const TQString& contentsType )
2292{
2293 kdDebug(5006) << "Adding subresource to parent: " << parent << " with name: " << resource << endl;
2294 kdDebug(5006) << "contents type: " << contentsType << endl;
2295 KMFolder *folder = findResourceFolder( parent );
2296 KMFolderDir *parentFolderDir = !parent.isEmpty() && folder ? folder->createChildFolder(): mFolderParentDir;
2297 if ( !parentFolderDir || parentFolderDir->hasNamedFolder( resource ) ) return false;
2298
2299 TQString msg;
2300 if ( parentFolderDir->owner() && !parentFolderDir->owner()->isValidName( resource, msg ) ) {
2301 KMessageBox::error( 0, msg );
2302 return false;
2303 }
2304
2305 KMFolderType type = mFolderType;
2306 if( type == KMFolderTypeUnknown ) type = KMFolderTypeMaildir;
2307
2308 KMFolder* newFolder = parentFolderDir->createFolder( resource, false, type );
2309 if ( !newFolder ) return false;
2310 if( mFolderType == KMFolderTypeImap )
2311 static_cast<KMFolderImap*>( folder->storage() )->createFolder( resource );
2312
2313 StorageFormat defaultFormat = GlobalSettings::self()->theIMAPResourceStorageFormat() == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
2314 setStorageFormat( newFolder, folder ? storageFormat( folder ) : defaultFormat );
2315 newFolder->storage()->setContentsType( folderContentsType( contentsType ) );
2316 newFolder->storage()->writeConfig();
2317 newFolder->open( "ical_subresource" );
2318 connectFolder( newFolder );
2319 reloadFolderTree();
2320
2321 return true;
2322}
2323
2324bool KMailICalIfaceImpl::removeSubresource( const TQString& location )
2325{
2326 kdDebug(5006) << k_funcinfo << endl;
2327
2328 KMFolder *folder = findResourceFolder( location );
2329
2330 // We don't allow the default folders to be deleted, so check for
2331 // those first. It would be nicer to produce a more meaningful error,
2332 // or prevent deletion of the builtin folders from the gui already.
2333 if ( !folder || isStandardResourceFolder( folder ) )
2334 return false;
2335
2336 // the folder will be removed, which implies closed, so make sure
2337 // nothing is using it anymore first
2338 subresourceDeleted( folderContentsType( folder->storage()->contentsType() ), location );
2339 mExtraFolders.remove( location );
2340 folder->disconnect( this );
2341
2342 if ( folder->folderType() == KMFolderTypeImap )
2343 kmkernel->imapFolderMgr()->remove( folder );
2344 else if ( folder->folderType() == KMFolderTypeCachedImap ) {
2345 // Deleted by user -> tell the account (see KMFolderCachedImap::listDirectory2)
2346 KMFolderCachedImap* storage = static_cast<KMFolderCachedImap*>( folder->storage() );
2347 KMAcctCachedImap* acct = storage->account();
2348 if ( acct )
2349 acct->addDeletedFolder( folder );
2350 kmkernel->dimapFolderMgr()->remove( folder );
2351 }
2352 return true;
2353}
2354
2355void KMailICalIfaceImpl::syncFolder(KMFolder * folder) const
2356{
2357 if ( kmkernel->isOffline() || !GlobalSettings::immediatlySyncDIMAPOnGroupwareChanges() )
2358 return;
2359 KMFolderCachedImap *dimapFolder = dynamic_cast<KMFolderCachedImap*>( folder->storage() );
2360 if ( !dimapFolder )
2361 return;
2362 // check if the folder exists already, otherwise sync its parent as well to create it
2363 if ( dimapFolder->imapPath().isEmpty() ) {
2364 if ( folder->parent() && folder->parent()->owner() )
2365 syncFolder( folder->parent()->owner() );
2366 else
2367 return;
2368 }
2369 dimapFolder->account()->processNewMailInFolder( folder );
2370}
2371
2372#include "kmailicalifaceimpl.moc"
The FolderStorage class is the bass class for the storage related aspects of a collection of mail (a ...
Definition: folderstorage.h:80
virtual KMMessage * readTemporaryMsg(int idx)
Load message from file and do NOT store it, only return it.
virtual void setContentsType(KMail::FolderContentsType type, bool quiet=false)
Set the type of contents held in this folder (mail, calendar, etc.)
KMail::FolderContentsType contentsType() const
virtual void writeConfig()
Write the config file.
KMail list that manages the contents of one directory that may contain folders and/or other directori...
Definition: kmfolderdir.h:16
virtual KMFolder * createFolder(const TQString &folderName, bool sysFldr=false, KMFolderType folderType=KMFolderTypeMbox)
Create a mail folder in this directory with given name.
Definition: kmfolderdir.cpp:95
KMFolder * owner() const
Returns the folder whose children we are holding.
Definition: kmfolderdir.h:59
virtual KMFolderNode * hasNamedFolder(const TQString &name)
Returns folder with given name or zero if it does not exist.
Mail folder.
Definition: kmfolder.h:69
TQString idString() const
Returns a string that can be used to identify this folder.
Definition: kmfolder.cpp:705
virtual TQString prettyURL() const
URL of the node for visualization purposes.
Definition: kmfolder.cpp:593
void ignoreJobsForMessage(KMMessage *)
Removes and deletes all jobs associated with the particular message.
Definition: kmfolder.cpp:341
virtual TQString label() const
Returns the label of the folder for visualization.
Definition: kmfolder.cpp:581
bool isValidName(const TQString &folderName, TQString &message)
Returns true if the name is valid for a child of this folder.
Definition: kmfolder.cpp:899
KMMsgInfo * unGetMsg(int idx)
Replace KMMessage with KMMsgInfo and delete KMMessage
Definition: kmfolder.cpp:326
int canAccess()
Check folder for permissions Returns zero if readable and writable.
Definition: kmfolder.cpp:484
int addMsg(KMMessage *msg, int *index_return=0)
Add the given message to the folder.
Definition: kmfolder.cpp:390
bool isMessage(int idx)
Checks if the message is already "gotten" with getMsg.
Definition: kmfolder.cpp:331
bool isSystemFolder() const
Returns true if the folder is a kmail system folder.
Definition: kmfolder.h:369
void close(const char *owner, bool force=false)
Close folder.
Definition: kmfolder.cpp:489
KMFolderDir * createChildFolder()
Create a child folder directory and associates it with this folder.
Definition: kmfolder.cpp:264
KMMessage * getMsg(int idx)
Read message at given index.
Definition: kmfolder.cpp:321
KMFolderType folderType() const
Returns the type of this folder.
Definition: kmfolder.cpp:233
int count(bool cache=false) const
Number of messages in this folder.
Definition: kmfolder.cpp:445
int open(const char *owner)
Open folder for access.
Definition: kmfolder.cpp:479
bool isWritable() const
Can we write into and delete from this folder (on IMAP that's not necessarily !isReadOnly())
Definition: kmfolder.cpp:571
TQString location() const
Returns full path to folder file.
Definition: kmfolder.cpp:243
void removeMsg(int i, bool imapQuiet=false)
Remove (first occurrence of) given message from the folder.
Definition: kmfolder.cpp:410
int find(const KMMsgBase *msg) const
Returns the index of the given message or -1 if not found.
Definition: kmfolder.cpp:435
This is a Mime Message.
Definition: kmmessage.h:68
DwBodyPart * getFirstDwBodyPart() const
Get the 1st DwBodyPart.
Definition: kmmessage.cpp:2848
TQCString typeStr() const
Get or set the 'Content-Type' header field The member functions that involve enumerated types (ints) ...
Definition: kmmessage.cpp:2391
void setBodyEncoded(const TQCString &aStr, DwEntity *entity=0)
Set the message body, encoding it according to the current content transfer encoding.
Definition: kmmessage.cpp:2719
void touch()
Touch the message - mark it as read.
Definition: kmmessage.h:158
static void bodyPart(DwBodyPart *aDwBodyPart, KMMessagePart *aPart, bool withBody=true)
Fill the KMMessagePart structure for a given DwBodyPart.
Definition: kmmessage.cpp:3108
void setAutomaticFields(bool isMultipart=false)
Set fields that are either automatically set (Message-id) or that do not change from one message to a...
Definition: kmmessage.cpp:1777
void setNeedsAssembly()
tell the message that internal data were changed (must be called after directly modifying message str...
Definition: kmmessage.cpp:2553
TQString subject() const
Get or set the 'Subject' header field.
Definition: kmmessage.cpp:2049
void removeHeaderField(const TQCString &name)
Remove header field with given name.
Definition: kmmessage.cpp:2317
TQCString subtypeStr() const
Subtype.
Definition: kmmessage.cpp:2428
void addDwBodyPart(DwBodyPart *aDwPart)
Append a DwBodyPart to the message.
Definition: kmmessage.cpp:3348
TQString bodyToUnicode(const TQTextCodec *codec=0) const
Returns the body part decoded to unicode.
Definition: kmmessage.cpp:4471
void addBodyPart(const KMMessagePart *aPart)
Append a body part to the message.
Definition: kmmessage.cpp:3356
bool transferInProgress() const
Return, if the message should not be deleted.
Definition: kmmessage.cpp:236
void deleteWhenUnused()
Delete this message as soon as it no longer in use.
Definition: kmmessage.cpp:4497
void cleanupHeader()
Removes empty fields from the header, e.g.
Definition: kmmessage.cpp:1754
DwHeaders & headers() const
get the DwHeaders (make sure to call setNeedsAssembly() function after directly modyfying internal da...
Definition: kmmessage.cpp:2546
bool isComplete() const
Return true if the complete message is available without referring to the backing store.
Definition: kmmessage.h:867
void initHeader(uint identity=0)
Initialize header fields.
Definition: kmmessage.cpp:1715
void setHeaderField(const TQCString &name, const TQString &value, HeaderFieldType type=Unstructured, bool prepend=false)
Set the header field with the given name to the given value.
Definition: kmmessage.cpp:2339
DwBodyPart * createDWBodyPart(const KMMessagePart *aPart)
Compose a DwBodyPart (needed for adding a part to the message).
Definition: kmmessage.cpp:3218
void getLocation(unsigned long key, KMFolder **retFolder, int *retIndex) const
Returns the folder the message represented by the serial number key is in and the index in that folde...
Definition: kmmsgdict.cpp:319
static const KMMsgDict * instance()
Access the globally unique MessageDict.
Definition: kmmsgdict.cpp:167
The implementation of the interface.
static KMMessage * findMessageBySerNum(TQ_UINT32 serNum, KMFolder *folder)
Find message matching a given serial number.
bool isResourceFolder(KMFolder *folder) const
Returns true if resource mode is enabled and folder is one of the resource folders.
KMFolder * folderFromType(const TQString &type, const TQString &folder)
Get the folder that holds type entries.
TQ_UINT32 update(const TQString &resource, TQ_UINT32 sernum, const TQString &subject, const TQString &plainTextBody, const TQMap< TQCString, TQString > &customHeaders, const TQStringList &attachmentURLs, const TQStringList &attachmentMimetypes, const TQStringList &attachmentNames, const TQStringList &deletedAttachments)
Update a kolab storage entry.
bool hideResourceAccountRoot(KMFolder *folder) const
Returns true if the given folder is the root of the groupware account, groupware folders are hidden,...
TQString folderPixmap(KFolderTreeItem::Type type) const
Returns the name of the standard icon for a folder of given type or TQString() if the type is no grou...
KMMessage * findMessageByUID(const TQString &uid, KMFolder *folder)
Find message matching a given UID.
KFolderTreeItem::Type folderType(KMFolder *folder) const
Returns the resource folder type.
void deleteMsg(KMMessage *msg)
Convenience function to delete a message.
void cleanup()
Disconnect all slots and close the dirs.
TQMap< TQ_UINT32, TQString > incidencesKolab(const TQString &mimetype, const TQString &resource, int startIndex, int nbMessages)
bool hideResourceFolder(KMFolder *folder) const
Returns true if isResourceFolder( folder ) returns true, and imap folders should be hidden.
TQString folderName(KFolderTreeItem::Type type, int language=-1) const
Returns the localized name of a folder of given type.
void folderContentsTypeChanged(KMFolder *, KMail::FolderContentsType)
Called when a folders contents have changed.
void setStorageFormat(KMFolder *folder, StorageFormat format)
Set the storage format of a given folder. Called when seeing the kolab annotation.
The account manager is responsible for creating accounts of various types via the factory method crea...
const KMAccount * next() const
Next account of the list.
const KMAccount * first() const
First account of the list.
This class takes a folder attribute string as argument and provides access to the single parts.
Definition: scalix.h:57
@ Ok
The user rights/ACL have been fetched from the server sucessfully.
Definition: acljobs.h:66
folderdiaquotatab.h
Definition: aboutdata.cpp:40