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 
77 using namespace KMail;
78 
79 TQMap<TQString, TQString> *KMailICalIfaceImpl::mSubResourceUINamesMap = new TQMap<TQString, TQString>;
80 
81 // Local helper methods
82 static void vPartMicroParser( const TQString& str, TQString& s );
83 static void reloadFolderTree();
84 
85 // The index in this array is the KMail::FolderContentsType enum
86 static 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 
101 static TQString folderContentsType( KMail::FolderContentsType type )
102 {
103  return s_folderContentsType[type].contentsTypeStr;
104 }
105 
106 static TQString folderKolabMimeType( KMail::FolderContentsType type )
107 {
108  return s_folderContentsType[type].mimetype;
109 }
110 
111 KMailICalIfaceImpl::StorageFormat KMailICalIfaceImpl::globalStorageFormat() const {
112  return GlobalSettings::self()->theIMAPResourceStorageFormat()
113  == GlobalSettings::EnumTheIMAPResourceStorageFormat::XML ? StorageXML : StorageIcalVcard;
114 }
115 
116 static 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 
124 static TQString localizedDefaultFolderName( KMail::FolderContentsType type )
125 {
126  return i18n( s_folderContentsType[type].translatedName );
127 }
128 
129 const char* KMailICalIfaceImpl::annotationForContentsType( KMail::FolderContentsType type )
130 {
131  return s_folderContentsType[type].annotation;
132 }
133 
134 ExtraFolder::ExtraFolder( KMFolder* f )
135  : folder( f )
136 {
137  folder->open("kmailicaliface::extrafolder");
138 }
139 
140 ExtraFolder::~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 
157 KMailICalIfaceImpl::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.
178 static 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
204 static 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
220 static 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
233 inline 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
241 bool 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
310 bool 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.
331 bool 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 
356 static 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 
387 static 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
405 TQ_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 
479 bool 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 
511 int 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 
533 TQMap<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
610 void 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 
649 static 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 
662 int KMailICalIfaceImpl::dimapAccounts()
663 {
664  return dimapAccountCount();
665 }
666 
667 static 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 */
718 TQValueList<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 
749 bool 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. */
778 bool 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. */
790 KMailICalIfaceImpl::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 
815 TQ_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 
933 KURL 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 
993 TQString 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 
1023 TQStringList 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 
1071 void 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
1082 void 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
1152 void 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
1199 void 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
1208 void 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 
1263 bool 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 
1284 KFolderTreeItem::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
1300 static TQMap<KFolderTreeItem::Type,TQString> folderNames[4];
1301 TQString 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 
1463 KMFolder* 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 
1479 KMailICalIfaceImpl::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 
1487 void 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 
1501 void 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 
1513 KMailICalIfaceImpl::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 
1530 void 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 
1539 void 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 
1554 void KMailICalIfaceImpl::folderDeletedOnServer( const KURL& folderURL )
1555 {
1556  triggerKolabFreeBusy( folderURL );
1557 }
1558 
1559 void 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 
1597 void 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!
1610 void KMailICalIfaceImpl::slotFolderRenamed()
1611 {
1612  const KMFolder* folder = static_cast<const KMFolder *>( sender() );
1613  slotFolderPropertiesChanged( const_cast<KMFolder*>( folder ) );
1614 }
1615 
1616 void 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 
1633 KMFolder* 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 
1656 void 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.
1669 static 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 
1687 void 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 
1960 void 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 
1975 KMFolder* 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 
2031 KMFolder* 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 
2084 void 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 
2116 static 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 
2136 TQString 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 
2155 static 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
2164 static 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
2194 static 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 
2212 KMailICalIfaceImpl::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. */
2250 bool 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 
2278 void KMailICalIfaceImpl::setResourceQuiet(bool q)
2279 {
2280  mResourceQuiet = q;
2281 }
2282 
2283 bool KMailICalIfaceImpl::isResourceQuiet() const
2284 {
2285  return mResourceQuiet;
2286 }
2287 
2288 
2289 bool 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 
2324 bool 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 
2355 void 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
virtual KMFolderNode * hasNamedFolder(const TQString &name)
Returns folder with given name or zero if it does not exist.
KMFolder * owner() const
Returns the folder whose children we are holding.
Definition: kmfolderdir.h:59
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 * first() const
First account of the list.
const KMAccount * next() const
Next 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