[Bug 104956] dimap: sudden mail loss
Till Adam
adam at kde.org
Sat Oct 21 09:34:20 UTC 2006
------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.
http://bugs.kde.org/show_bug.cgi?id=104956
adam kde org changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|NEW |RESOLVED
Resolution| |FIXED
------- Additional Comments From adam kde org 2006-10-21 11:34 -------
SVN commit 597659 by tilladam:
Add more uidcache file handling defensiveness and some debugging facilities.
Patch tested by me for a few weeks, initial reactions from the testers seem
to say it helps.
BUG: 104956
M +81 -19 kmfoldercachedimap.cpp
M +5 -0 kmfoldercachedimap.h
--- branches/KDE/3.5/kdepim/kmail/kmfoldercachedimap.cpp #597658:597659
@ -75,6 +75,7 @
#include <globalsettings.h>
#define UIDCACHE_VERSION 1
+#define MAIL_LOSS_DEBUGGING 0
static QString incidencesForToString( KMFolderCachedImap::IncidencesFor r ) {
switch (r) {
@ -150,10 +151,22 @
mFolderRemoved( false ),
/*mHoldSyncs( false ),*/ mRecurse( true ),
mStatusChangedLocally( false ), mAnnotationFolderTypeChanged( false ),
- mIncidencesForChanged( false ), mPersonalNamespacesCheckDone( true )
+ mIncidencesForChanged( false ), mPersonalNamespacesCheckDone( true ),
+ mFoundAnIMAPDigest( false )
{
setUidValidity("");
- readUidCache();
+ // if we fail to read a uid file but there is one, nuke it
+ if ( readUidCache() == -1 ) {
+ if ( QFile::exists( uidCacheLocation() ) ) {
+ KMessageBox::error( 0,
+ i18n( "The UID cache file for folder %1 could not be read. There "
+ "could be a problem with file system permission, or it is corrupted."
+ ).arg( folder->prettyURL() ) );
+ // try to unlink it, in case it was corruped. If it couldn't be read
+ // because of permissions, this will fail, which is fine
+ unlink( QFile::encodeName( uidCacheLocation() ) );
+ }
+ }
mProgress = 0;
}
@ -306,7 +319,7 @
if( uidValidity().isEmpty() || uidValidity() == "INVALID" ) {
// No info from the server yet, remove the file.
if( QFile::exists( uidCacheLocation() ) )
- unlink( QFile::encodeName( uidCacheLocation() ) );
+ return unlink( QFile::encodeName( uidCacheLocation() ) );
return 0;
}
@ -317,17 +330,23 @
str << uidValidity() << endl;
str << lastUid() << endl;
uidcache.flush();
- fsync( uidcache.handle() ); /* this is probably overkill */
- uidcache.close();
- return 0;
- } else {
- return errno; /* does QFile set errno? */
+ if ( uidcache.status() == IO_Ok ) {
+ fsync( uidcache.handle() ); /* this is probably overkill */
+ uidcache.close();
+ if ( uidcache.status() == IO_Ok )
+ return 0;
+ }
}
+ KMessageBox::error( 0,
+ i18n( "The UID cache file for folder %1 could not be written. There "
+ "could be a problem with file system permission." ).arg( folder()->prettyURL() ) );
+
+ return -1;
}
void KMFolderCachedImap::reloadUidMap()
{
- kdDebug(5006) << "Reloading Uid Map " << endl;
+ //kdDebug(5006) << "Reloading Uid Map " << endl;
uidMap.clear();
open();
for( int i = 0; i < count(); ++i ) {
@ -448,7 +467,8 @
{
killTimer( uidWriteTimer );
uidWriteTimer = -1;
- writeUidCache();
+ if ( writeUidCache() == -1 )
+ unlink( QFile::encodeName( uidCacheLocation() ) );
}
ulong KMFolderCachedImap::lastUid()
@ -467,10 +487,22 @
QMap<ulong,int>::Iterator it = uidMap.find( uid );
if( it != uidMap.end() ) {
KMMsgBase *msg = getMsgBase( *it );
+#ifdef MAIL_LOSS_DEBUGGING
+ kdDebug(5006) << "UID " << uid << " is supposed to be in the map" << endl;
+ kdDebug(5006) << "UID's index is to be " << *it << endl;
+ kdDebug(5006) << "There is a message there? " << (msg != 0) << endl;
+ if ( msg ) {
+ kdDebug(5006) << "Its UID is: " << msg->UID() << endl;
+ }
+#endif
+
if( msg && msg->UID() == uid )
return msg;
+ kdDebug(5006) << "########## Didn't find uid: " << uid << "in cache athough it's supposed to be there!" << endl;
} else {
+#ifdef MAIL_LOSS_DEBUGGING
kdDebug(5006) << "Didn't find uid: " << uid << "in cache!" << endl;
+#endif
}
// Not found by now
// if( mapReloaded )
@ -482,8 +514,10 @
if( it != uidMap.end() )
// Since the uid map is just rebuilt, no need for the sanity check
return getMsgBase( *it );
+#ifdef MAIL_LOSS_DEBUGGING
else
kdDebug(5006) << "Reloaded, but stil didn't find uid: " << uid << endl;
+#endif
// Then it's not here
return 0;
}
@ -841,9 +875,14 @
to be deleted on the server has been deleted, adjust our local notion of the
highes uid seen thus far. */
slotUpdateLastUid();
- if( mLastUid == 0 && uidWriteTimer == -1 )
+ if( mLastUid == 0 && uidWriteTimer == -1 ) {
// This is probably a new and empty folder. Write the UID cache
- writeUidCache();
+ if ( writeUidCache() == -1 ) {
+ resetSyncState();
+ emit folderComplete( this, false );
+ return;
+ }
+ }
}
}
@ -1209,9 +1248,10 @
void KMFolderCachedImap::slotImapStatusChanged(KMFolder* folder, const QString&, bool cont)
{
if ( mSyncState == SYNC_STATE_INITIAL ){
- kdDebug(5006) << "IMAP status changed but reset " << endl;
+ //kdDebug(5006) << "IMAP status changed but reset " << endl;
return; // we were reset
}
+ //kdDebug(5006) << "IMAP status changed for folder: " << folder->prettyURL() << endl;
if ( folder->storage() == this ) {
--mStatusFlagsJobs;
if ( mStatusFlagsJobs == 0 || !cont ) // done or aborting
@ -1220,6 +1260,7 @
if ( mStatusFlagsJobs == 0 && cont ) {
mProgress += 5;
serverSyncInternal();
+ //kdDebug(5006) << "Proceeding with mailcheck." << endl;
}
}
}
@ -1288,15 +1329,24 @
// them one by one because the index list can get resized under
// us. So use msg pointers instead
+ QStringList uids;
QMap<ulong,int>::const_iterator it = uidMap.constBegin();
for( ; it != uidMap.end(); it++ ) {
ulong uid ( it.key() );
- if( uid!=0 && !uidsOnServer.find( uid ) )
+ if( uid!=0 && !uidsOnServer.find( uid ) ) {
+ uids << QString::number( uid );
msgsForDeletion.append( getMsg( *it ) );
+ }
}
if( !msgsForDeletion.isEmpty() ) {
- removeMsg( msgsForDeletion );
+#ifdef MAIL_LOSS_DEBUGGING
+ if ( KMessageBox::warningYesNo(
+ 0, i18n( "<qt><p>Mails on the server in folder <b>%1</b> were deleted. "
+ "Do you want to delete them locally?<br>UIDs: %2</p></qt>" )
+ .arg( folder()->prettyURL() ).arg( uids.join(",") ) ) == KMessageBox::Yes )
+#endif
+ removeMsg( msgsForDeletion );
}
/* Delete messages from the server that we dont have anymore */
@ -1370,6 +1420,8 @
uidsForDeletionOnServer.clear();
mMsgsForDownload.clear();
mUidsForDownload.clear();
+ // listing is only considered successful if saw a syntactically correct imapdigest
+ mFoundAnIMAPDigest = false;
CachedImapJob* job = new CachedImapJob( FolderJob::tListMessages, this );
connect( job, SIGNAL( result(KMail::FolderJob *) ),
@ -1415,6 +1467,7 @
setReadOnly( access == "Read only" );
}
(*it).cdata.remove(0, pos);
+ mFoundAnIMAPDigest = true;
}
pos = (*it).cdata.find("\r\n--IMAPDIGEST", 1);
// Start with something largish when rebuilding the cache
@ -1432,7 +1485,7 @
if( uid != 0 ) {
if ( uidsOnServer.count() == uidsOnServer.size() ) {
uidsOnServer.resize( KMail::nextPrime( uidsOnServer.size() * 2 ) );
- kdDebug( 5006 ) << "Resizing to: " << uidsOnServer.size() << endl;
+ //kdDebug( 5006 ) << "Resizing to: " << uidsOnServer.size() << endl;
}
uidsOnServer.insert( uid, &v );
}
@ -1451,7 +1504,9 @
KMMsgBase *existingMessage = findByUID(uid);
if( !existingMessage ) {
if ( mUserRights <= 0 || ( mUserRights & KMail::ACLJobs::Delete ) ) {
- // kdDebug(5006) << "message with uid " << uid << " is gone from local cache. Must be deleted on server!!!" << endl;
+#ifdef MAIL_LOSS_DEBUGGING
+ kdDebug(5006) << "message with uid " << uid << " is gone from local cache. Must be deleted on server!!!" << endl;
+#endif
uidsForDeletionOnServer << uid;
} else {
redownload = true;
@ -1490,6 +1545,13 @
void KMFolderCachedImap::getMessagesResult( KMail::FolderJob *job, bool lastSet )
{
mProgress += 10;
+ if ( !job->error() && !mFoundAnIMAPDigest ) {
+ kdWarning(5006) << "######## Folderlisting did not complete, but there was no error! "
+ "Aborting sync of folder: " << folder()->prettyURL() << endl;
+#ifdef MAIL_LOSS_DEBUGGING
+ kmkernel->emergencyExit( i18n("Folder listing failed in interesting ways." ) );
+#endif
+ }
if( job->error() ) { // error listing messages but the user chose to continue
mContentState = imapNoInformation;
mSyncState = SYNC_STATE_HANDLE_INBOX; // be sure not to continue in this folder
@ -1741,7 +1803,7 @
KMFolderNode *node;
bool root = ( this == mAccount->rootFolder() );
if ( root && !mAccount->hasInbox() ) {
- kdDebug(5006) << "check INBOX" << endl;
+ //kdDebug(5006) << "check INBOX" << endl;
// create the INBOX
for (node = folder()->child()->first(); node; node = folder()->child()->next())
if (!node->isDir() && node->name() == "INBOX") break;
@ -2216,7 +2278,7 @
void
KMFolderCachedImap::slotAnnotationChanged( const QString& entry, const QString& attribute, const QString& value )
{
- kdDebug(5006) << k_funcinfo << entry << " " << attribute << " " << value << endl;
+ //kdDebug(5006) << k_funcinfo << entry << " " << attribute << " " << value << endl;
if ( entry == KOLAB_FOLDERTYPE )
mAnnotationFolderTypeChanged = false;
else if ( entry == KOLAB_INCIDENCESFOR ) {
--- branches/KDE/3.5/kdepim/kmail/kmfoldercachedimap.h #597658:597659
@ -445,6 +445,11 @
mLastUid. See above for details. */
ulong mTentativeHighestUid;
+ /** Used to determine whether listing messages yielded a sensible result.
+ * Only then is the deletion o messages (which relies on succesful
+ * listing) attempted, during the sync. */
+ bool mFoundAnIMAPDigest;
+
int mUserRights;
ACLList mACLList;
More information about the pkg-kde-bugs-fwd
mailing list