<commit_before>/**
 *  kmfoldercachedimap.cpp
 *
 *  Copyright (c) 2002-2004 <NAME> <<EMAIL>>
 *  Copyright (c) 2002-2003 <NAME> <<EMAIL>>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of this program with any edition of
 *  the Qt library by Trolltech AS, Norway (or with modified versions
 *  of Qt that use the same license as Qt), and distribute linked
 *  combinations including the two.  You must obey the GNU General
 *  Public License in all respects for all of the code used other than
 *  Qt.  If you modify this file, you may extend this exception to
 *  your version of the file, but you are not obligated to do so.  If
 *  you do not wish to do so, delete this exception statement from
 *  your version.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <errno.h>

#include "kmkernel.h"
#include "kmfoldercachedimap.h"
#include "undostack.h"
#include "kmfoldermgr.h"
#include "kmmessage.h"
#include "kmacctcachedimap.h"
#include "kmacctmgr.h"
#include "kmailicalifaceimpl.h"
#include "kmfolder.h"
#include "kmdict.h"
#include "acljobs.h"
#include "broadcaststatus.h"
using KPIM::BroadcastStatus;
#include "progressmanager.h"

using KMail::CachedImapJob;
using KMail::ImapAccountBase;
#include "listjob.h"
using KMail::ListJob;

#include <kapplication.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kdebug.h>
#include <kconfig.h>
#include <kio/global.h>
#include <kio/scheduler.h>
#include <qbuffer.h>
#include <qfile.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qvaluelist.h>
#include "annotationjobs.h"
#include <libkdepim/kincidencechooser.h>
using namespace KMail;
#include <globalsettings.h>

#define UIDCACHE_VERSION 1

static QString incidencesForToString( KMFolderCachedImap::IncidencesFor r ) {
  switch (r) {
  case KMFolderCachedImap::IncForNobody: return "nobody";
  case KMFolderCachedImap::IncForAdmins: return "admins";
  case KMFolderCachedImap::IncForReaders: return "readers";
  }
  return QString::null; // can't happen
}

static KMFolderCachedImap::IncidencesFor incidencesForFromString( const QString& str ) {
  if ( str == "nobody" ) return KMFolderCachedImap::IncForNobody;
  if ( str == "admins" ) return KMFolderCachedImap::IncForAdmins;
  if ( str == "readers" ) return KMFolderCachedImap::IncForReaders;
  return KMFolderCachedImap::IncForAdmins; // by default
}

DImapTroubleShootDialog::DImapTroubleShootDialog( QWidget* parent,
                                                  const char* name )
  : KDialogBase( Plain, i18n( "Troubleshooting IMAP Cache" ),
                 Cancel | User1 | User2, Cancel, parent, name, true ),
    rc( Cancel )
{
  QFrame* page = plainPage();
  QVBoxLayout *topLayout = new QVBoxLayout( page, 0 );
  QString txt = i18n( "<p><b>Troubleshooting the IMAP cache.</b></p>"
                      "<p>If you have problems with synchronizing an IMAP "
                      "folder, you should first try rebuilding the index "
                      "file. This will take some time to rebuild, but will "
                      "not cause any problems.</p><p>If that is not enough, "
                      "you can try refreshing the IMAP cache. If you do this, "
                      "you will loose all your local changes for this folder "
                      "and all it's subfolders.</p>" );
  topLayout->addWidget( new QLabel( txt, page ) );
  enableButtonSeparator( true );

  setButtonText( User1, i18n( "&Refresh Cache" ) );
  setButtonText( User2, i18n( "Rebuild &Index" ) );

  connect( this, SIGNAL( user1Clicked () ), this, SLOT( slotRebuildCache() ) );
  connect( this, SIGNAL( user2Clicked () ), this, SLOT( slotRebuildIndex() ) );
}

int DImapTroubleShootDialog::run()
{
  DImapTroubleShootDialog d;
  d.exec();
  return d.rc;
}

void DImapTroubleShootDialog::slotRebuildCache()
{
  rc = User1;
  done( User1 );
}

void DImapTroubleShootDialog::slotRebuildIndex()
{
  rc = User2;
  done( User2 );
}


KMFolderCachedImap::KMFolderCachedImap( KMFolder* folder, const char* aName )
  : KMFolderMaildir( folder, aName ),
    mSyncState( SYNC_STATE_INITIAL ), mContentState( imapNoInformation ),
    mSubfolderState( imapNoInformation ),
    mIncidencesFor( IncForAdmins ),
    mIsSelected( false ),
    mCheckFlags( true ), mAccount( NULL ), uidMapDirty( true ),
    uidWriteTimer( -1 ), mLastUid( 0 ), mTentativeHighestUid( 0 ),
    mUserRights( 0 ), mSilentUpload( false ),
    mFolderRemoved( false ),
    /*mHoldSyncs( false ),*/ mRecurse( true ),
    mStatusChangedLocally( false ), mAnnotationFolderTypeChanged( false ),
    mIncidencesForChanged( false )
{
  setUidValidity("");
  readUidCache();

  mProgress = 0;
}

KMFolderCachedImap::~KMFolderCachedImap()
{
  if( !mFolderRemoved ) {
    writeConfig();
    writeUidCache();
  }

  if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
}

void KMFolderCachedImap::initializeFrom( KMFolderCachedImap* parent )
{
  setAccount( parent->account() );
  // Now that we have an account, tell it that this folder was created:
  // if this folder was just removed, then we don't really want to remove it from the server.
  mAccount->removeDeletedFolder( imapPath() );
  setUserRights( parent->userRights() );
}

void KMFolderCachedImap::readConfig()
{
  KConfig* config = KMKernel::config();
  KConfigGroupSaver saver( config, "Folder-" + folder()->idString() );
  if( mImapPath.isEmpty() ) mImapPath = config->readEntry( "ImapPath" );
  if( QString( name() ).upper() == "INBOX" && mImapPath == "/INBOX/" )
  {
    folder()->setLabel( i18n( "inbox" ) );
    // for the icon
    folder()->setSystemFolder( true );
  }
  mNoContent = config->readBoolEntry( "NoContent", false );
  mReadOnly = config->readBoolEntry( "ReadOnly", false );

  if ( mAnnotationFolderType != "FROMSERVER" ) {
    mAnnotationFolderType = config->readEntry( "Annotation-FolderType" );
    kdDebug(5006) << ( mImapPath.isEmpty() ? label() : mImapPath )
                  << " readConfig: mAnnotationFolderType=" << mAnnotationFolderType << endl;
  }
  if ( !mAnnotationFolderType.isEmpty() )
    kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );

  mIncidencesFor = incidencesForFromString( config->readEntry( "IncidencesFor" ) );
  kdDebug(5006) << ( mImapPath.isEmpty() ? label() : mImapPath )
                << " readConfig: mIncidencesFor=" << mIncidencesFor << endl;

  KMFolderMaildir::readConfig();

  mStatusChangedLocally =
    config->readBoolEntry( "StatusChangedLocally", false );

  mAnnotationFolderTypeChanged = config->readBoolEntry( "AnnotationFolderTypeChanged", false );
  mIncidencesForChanged = config->readBoolEntry( "IncidencesForChanged", false );
}

void KMFolderCachedImap::writeConfig()
{
  KConfigGroup configGroup( KMKernel::config(), "Folder-" + folder()->idString() );
  configGroup.writeEntry( "ImapPath", mImapPath );
  configGroup.writeEntry( "NoContent", mNoContent );
  configGroup.writeEntry( "ReadOnly", mReadOnly );
  configGroup.writeEntry( "StatusChangedLocally", mStatusChangedLocally );
  writeAnnotationConfig();
  KMFolderMaildir::writeConfig();
}

void KMFolderCachedImap::writeAnnotationConfig()
{
  KConfigGroup configGroup( KMKernel::config(), "Folder-" + folder()->idString() );
  configGroup.writeEntry( "AnnotationFolderTypeChanged", mAnnotationFolderTypeChanged );
  configGroup.writeEntry( "Annotation-FolderType", mAnnotationFolderType );
  configGroup.writeEntry( "IncidencesForChanged", mIncidencesForChanged );
  configGroup.writeEntry( "IncidencesFor", incidencesForToString( mIncidencesFor ) );
}

void KMFolderCachedImap::remove()
{
  mFolderRemoved = true;

  QString part1 = folder()->path() + "/." + dotEscape(name());
  QString uidCacheFile = part1 + ".uidcache";
  // This is the account folder of an account that was just removed
  // When this happens, be sure to delete all traces of the cache
  if( QFile::exists(uidCacheFile) )
    unlink( QFile::encodeName( uidCacheFile ) );
  KIO::del( KURL::fromPathOrURL( part1 + ".directory" ) );

  FolderStorage::remove();
}

QString KMFolderCachedImap::uidCacheLocation() const
{
  QString sLocation(folder()->path());
  if (!sLocation.isEmpty()) sLocation += '/';
  return sLocation + '.' + dotEscape(fileName()) + ".uidcache";
}

int KMFolderCachedImap::readUidCache()
{
  QFile uidcache( uidCacheLocation() );<commit_msg>Persist the user rights to the config file, since the alarm relevance checking needs them before the first sync already.<commit_after>/**
 *  kmfoldercachedimap.cpp
 *
 *  Copyright (c) 2002-2004 <NAME> <<EMAIL>>
 *  Copyright (c) 2002-2003 <NAME> <<EMAIL>>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of this program with any edition of
 *  the Qt library by Trolltech AS, Norway (or with modified versions
 *  of Qt that use the same license as Qt), and distribute linked
 *  combinations including the two.  You must obey the GNU General
 *  Public License in all respects for all of the code used other than
 *  Qt.  If you modify this file, you may extend this exception to
 *  your version of the file, but you are not obligated to do so.  If
 *  you do not wish to do so, delete this exception statement from
 *  your version.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <errno.h>

#include "kmkernel.h"
#include "kmfoldercachedimap.h"
#include "undostack.h"
#include "kmfoldermgr.h"
#include "kmmessage.h"
#include "kmacctcachedimap.h"
#include "kmacctmgr.h"
#include "kmailicalifaceimpl.h"
#include "kmfolder.h"
#include "kmdict.h"
#include "acljobs.h"
#include "broadcaststatus.h"
using KPIM::BroadcastStatus;
#include "progressmanager.h"

using KMail::CachedImapJob;
using KMail::ImapAccountBase;
#include "listjob.h"
using KMail::ListJob;

#include <kapplication.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kdebug.h>
#include <kconfig.h>
#include <kio/global.h>
#include <kio/scheduler.h>
#include <qbuffer.h>
#include <qfile.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qvaluelist.h>
#include "annotationjobs.h"
#include <libkdepim/kincidencechooser.h>
using namespace KMail;
#include <globalsettings.h>

#define UIDCACHE_VERSION 1

static QString incidencesForToString( KMFolderCachedImap::IncidencesFor r ) {
  switch (r) {
  case KMFolderCachedImap::IncForNobody: return "nobody";
  case KMFolderCachedImap::IncForAdmins: return "admins";
  case KMFolderCachedImap::IncForReaders: return "readers";
  }
  return QString::null; // can't happen
}

static KMFolderCachedImap::IncidencesFor incidencesForFromString( const QString& str ) {
  if ( str == "nobody" ) return KMFolderCachedImap::IncForNobody;
  if ( str == "admins" ) return KMFolderCachedImap::IncForAdmins;
  if ( str == "readers" ) return KMFolderCachedImap::IncForReaders;
  return KMFolderCachedImap::IncForAdmins; // by default
}

DImapTroubleShootDialog::DImapTroubleShootDialog( QWidget* parent,
                                                  const char* name )
  : KDialogBase( Plain, i18n( "Troubleshooting IMAP Cache" ),
                 Cancel | User1 | User2, Cancel, parent, name, true ),
    rc( Cancel )
{
  QFrame* page = plainPage();
  QVBoxLayout *topLayout = new QVBoxLayout( page, 0 );
  QString txt = i18n( "<p><b>Troubleshooting the IMAP cache.</b></p>"
                      "<p>If you have problems with synchronizing an IMAP "
                      "folder, you should first try rebuilding the index "
                      "file. This will take some time to rebuild, but will "
                      "not cause any problems.</p><p>If that is not enough, "
                      "you can try refreshing the IMAP cache. If you do this, "
                      "you will loose all your local changes for this folder "
                      "and all it's subfolders.</p>" );
  topLayout->addWidget( new QLabel( txt, page ) );
  enableButtonSeparator( true );

  setButtonText( User1, i18n( "&Refresh Cache" ) );
  setButtonText( User2, i18n( "Rebuild &Index" ) );

  connect( this, SIGNAL( user1Clicked () ), this, SLOT( slotRebuildCache() ) );
  connect( this, SIGNAL( user2Clicked () ), this, SLOT( slotRebuildIndex() ) );
}

int DImapTroubleShootDialog::run()
{
  DImapTroubleShootDialog d;
  d.exec();
  return d.rc;
}

void DImapTroubleShootDialog::slotRebuildCache()
{
  rc = User1;
  done( User1 );
}

void DImapTroubleShootDialog::slotRebuildIndex()
{
  rc = User2;
  done( User2 );
}


KMFolderCachedImap::KMFolderCachedImap( KMFolder* folder, const char* aName )
  : KMFolderMaildir( folder, aName ),
    mSyncState( SYNC_STATE_INITIAL ), mContentState( imapNoInformation ),
    mSubfolderState( imapNoInformation ),
    mIncidencesFor( IncForAdmins ),
    mIsSelected( false ),
    mCheckFlags( true ), mAccount( NULL ), uidMapDirty( true ),
    uidWriteTimer( -1 ), mLastUid( 0 ), mTentativeHighestUid( 0 ),
    mUserRights( 0 ), mSilentUpload( false ),
    mFolderRemoved( false ),
    /*mHoldSyncs( false ),*/ mRecurse( true ),
    mStatusChangedLocally( false ), mAnnotationFolderTypeChanged( false ),
    mIncidencesForChanged( false )
{
  setUidValidity("");
  readUidCache();

  mProgress = 0;
}

KMFolderCachedImap::~KMFolderCachedImap()
{
  if( !mFolderRemoved ) {
    writeConfig();
    writeUidCache();
  }

  if (kmkernel->undoStack()) kmkernel->undoStack()->folderDestroyed( folder() );
}

void KMFolderCachedImap::initializeFrom( KMFolderCachedImap* parent )
{
  setAccount( parent->account() );
  // Now that we have an account, tell it that this folder was created:
  // if this folder was just removed, then we don't really want to remove it from the server.
  mAccount->removeDeletedFolder( imapPath() );
  setUserRights( parent->userRights() );
}

void KMFolderCachedImap::readConfig()
{
  KConfig* config = KMKernel::config();
  KConfigGroupSaver saver( config, "Folder-" + folder()->idString() );
  if( mImapPath.isEmpty() ) mImapPath = config->readEntry( "ImapPath" );
  if( QString( name() ).upper() == "INBOX" && mImapPath == "/INBOX/" )
  {
    folder()->setLabel( i18n( "inbox" ) );
    // for the icon
    folder()->setSystemFolder( true );
  }
  mNoContent = config->readBoolEntry( "NoContent", false );
  mReadOnly = config->readBoolEntry( "ReadOnly", false );

  if ( mAnnotationFolderType != "FROMSERVER" ) {
    mAnnotationFolderType = config->readEntry( "Annotation-FolderType" );
    kdDebug(5006) << ( mImapPath.isEmpty() ? label() : mImapPath )
                  << " readConfig: mAnnotationFolderType=" << mAnnotationFolderType << endl;
  }
  if ( !mAnnotationFolderType.isEmpty() )
    kmkernel->iCalIface().setStorageFormat( folder(), KMailICalIfaceImpl::StorageXML );

  mIncidencesFor = incidencesForFromString( config->readEntry( "IncidencesFor" ) );
  kdDebug(5006) << ( mImapPath.isEmpty() ? label() : mImapPath )
                << " readConfig: mIncidencesFor=" << mIncidencesFor << endl;

  mUserRights = config->readNumEntry( "UserRights", 0 ); // default is we don't know 

  KMFolderMaildir::readConfig();

  mStatusChangedLocally =
    config->readBoolEntry( "StatusChangedLocally", false );

  mAnnotationFolderTypeChanged = config->readBoolEntry( "AnnotationFolderTypeChanged", false );
  mIncidencesForChanged = config->readBoolEntry( "IncidencesForChanged", false );
}

void KMFolderCachedImap::writeConfig()
{
  KConfigGroup configGroup( KMKernel::config(), "Folder-" + folder()->idString() );
  configGroup.writeEntry( "ImapPath", mImapPath );
  configGroup.writeEntry( "NoContent", mNoContent );
  configGroup.writeEntry( "ReadOnly", mReadOnly );
  configGroup.writeEntry( "StatusChangedLocally", mStatusChangedLocally );
  writeAnnotationConfig();
  KMFolderMaildir::writeConfig();
}

void KMFolderCachedImap::writeAnnotationConfig()
{
  KConfigGroup configGroup( KMKernel::config(), "Folder-" + folder()->idString() );
  configGroup.writeEntry( "AnnotationFolderTypeChanged", mAnnotationFolderTypeChanged );
  configGroup.writeEntry( "Annotation-FolderType", mAnnotationFolderType );
  configGroup.writeEntry( "IncidencesForChanged", mIncidencesForChanged );
  configGroup.writeEntry( "IncidencesFor", incidencesForToString( mIncidencesFor ) );
  configGroup.writeEntry( "UserRights", mUserRights );
}

void KMFolderCachedImap::remove()
{
  mFolderRemoved = true;

  QString part1 = folder()->path() + "/." + dotEscape(name());
  QString uidCacheFile = part1 + ".uidcache";
  // This is the account folder of an account that was just removed
  // When this happens, be sure to delete all traces of the cache
  if( QFile::exists(uidCacheFile) )
    unlink( QFile::encodeName( uidCacheFile ) );
  KIO::del( KURL::fromPathOrURL( part1 + ".directory" ) );

  FolderStorage::remove();
}

QString KMFolderCachedImap::uidCacheLocation() const
{
  QString sLocation(folder()->path());
  if (!sLocation.isEmpty()) sLocation += '/';
  return sLocation + '.' + dotEscape(fileName()) + ".uidcache";
}

int KMFolderCachedImap::readUidCache()
{
  QFile uidcache( uidCacheLocation() );
{'fraction_non_alphanumeric': 0.1207524601750666, 'fraction_numerical': 0.007557222856521503, 'mean_word_length': 4.2063402207755445, 'pattern_counts': {'":': 0, '<': 95, '<?xml version=': 0, '>': 110, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1526508', 'n_tokens_mistral': 6028, 'n_tokens_neox': 5796, 'n_words': 1599}