[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kmail-devel
Subject:    Re: [Bug 48307] kmail crashed after changing from an imap folder busy with copying to a local local
From:       Carsten Burghardt <cb () magic-shop ! de>
Date:       2002-10-14 20:51:03
[Download RAW message or body]

On Monday 14 October 2002 12:53, Carsten Burghardt wrote:
> ------- You are receiving this mail because: -------
> You are the assignee for the bug, or are watching the assignee.
>
> http://bugs.kde.org/show_bug.cgi?id=48307
> burghardt@kde.org changed:
>
>            What    |Removed                     |Added
> ---------------------------------------------------------------------------
>- Status|REOPENED                    |ASSIGNED
>           Component|general                     |IMAP
>
>
>
> ------- Additional Comments From burghardt@kde.org  2002-10-14 12:53
> ------- OK, found the bug. Will be fixed soon.

The attached patch should fix it. It also contains the undo-changes as I was 
too lazy to separate them.
As I didn't find comments or documentation about the contentState-flag I 
assume that I can use it in this case. I set the contentState to 
imapInProgress if there is any move/copy operation and if close is called 
during such operations it is deferred.

-- 
Regards,

Carsten Burghardt
["kmfolderimap.diff" (text/x-diff)]

Index: kdenetwork/kmail/kmfolderimap.cpp
===================================================================
RCS file: /home/kde/kdenetwork/kmail/kmfolderimap.cpp,v
retrieving revision 1.72
diff -u -3 -p -r1.72 kmfolderimap.cpp
--- kdenetwork/kmail/kmfolderimap.cpp	2002/10/11 22:36:19	1.72
+++ kdenetwork/kmail/kmfolderimap.cpp	2002/10/14 20:42:43
@@ -47,6 +47,7 @@ KMFolderImap::KMFolderImap(KMFolderDir* 
   mIsSelected = FALSE;
   mLastUid = 0;
   mCheckFlags = TRUE;
+  mDeferredClose = FALSE;
 
   KConfig* config = kapp->config();
   KConfigGroupSaver saver(config, "Folder-" + idString());
@@ -165,25 +166,45 @@ void KMFolderImap::removeMsg(QPtrList<KM
 void KMFolderImap::addMsgQuiet(KMMessage* aMsg)
 {
   KMFolder *folder = aMsg->parent();
-  if (folder) kernel->undoStack()->pushAction( aMsg->getMsgSerNum(), folder, this );
-  if (folder) folder->take(folder->find(aMsg));
+  mContentState = imapFinished;
+  if (folder) 
+  {
+    if (aMsg->enableUndo())
+    {
+      kernel->undoStack()->pushAction( aMsg->getMsgSerNum(), folder, this );
+    } else {
+      aMsg->setEnableUndo(true);
+    }
+    folder->take(folder->find(aMsg));
+  }
   delete aMsg;
   aMsg = 0;
   getFolder();
+  if (mDeferredClose) close();
 }
 
 //-----------------------------------------------------------------------------
 void KMFolderImap::addMsgQuiet(QPtrList<KMMessage> msgList)
 {
   KMFolder *folder = msgList.first()->parent();
-  for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
+  mContentState = imapFinished;
+  if (folder)
   {
-    kernel->undoStack()->pushAction( msg->getMsgSerNum(), folder, this );
+    for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
+    {
+      if (msg->enableUndo())
+      {
+        kernel->undoStack()->pushAction( msg->getMsgSerNum(), folder, this );
+      } else {
+        msg->setEnableUndo(true);
+      }
+    }
+    folder->take(msgList);
   }
-  if (folder) folder->take(msgList);
   msgList.setAutoDelete(true);
   msgList.clear();
   getFolder();
+  if (mDeferredClose) close();
 }
 
 //-----------------------------------------------------------------------------
@@ -201,6 +222,7 @@ int KMFolderImap::addMsg(QPtrList<KMMess
   // make sure the messages won't be deleted while we work with them
   for ( KMMessage* msg = msgList.first(); msg; msg = msgList.next() )
     msg->setTransferInProgress(true);
+  mContentState = imapInProgress;
 
   KMImapJob *imapJob = 0;
   if (msgParent)
@@ -237,7 +259,7 @@ int KMFolderImap::addMsg(QPtrList<KMMess
             // we need the messages that belong to the current set to pass them to \
                the ImapJob
             QPtrList<KMMessage> temp_msgs = splitMessageList(*it, msgList);
 
-            imapJob = new KMImapJob(temp_msgs, *it, KMImapJob::tCopyMessage, this);
+            imapJob = new KMImapJob(temp_msgs, *it, KMImapJob::tMoveMessage, this);
             connect(imapJob, SIGNAL(messageCopied(QPtrList<KMMessage>)),
                 SLOT(addMsgQuiet(QPtrList<KMMessage>)));
           }
@@ -284,6 +306,7 @@ void KMFolderImap::copyMsg(QPtrList<KMMe
   QValueList<int> uids;
   getUids(msgList, uids);
   QStringList sets = makeSets(uids, false);
+  mContentState = imapInProgress;
   for ( QStringList::Iterator it = sets.begin(); it != sets.end(); ++it )
   {
     // we need the messages that belong to the current set to pass them to the \
ImapJob @@ -594,8 +617,10 @@ kdDebug(5006) << "KMFolderImap::slotChec
     QString startUid;
     if (uidValidity() != uidv)
     {
+      // uidValidity changed
       expunge();
       mLastUid = 0;
+      uidmap.clear();
     } else {
       if (!mCheckFlags)
         startUid = QString::number(lastUid() + 1);
@@ -851,7 +876,18 @@ void KMFolderImap::slotGetMessagesData(K
     }
     else {
       msg->setStatus(flagsToStatus(flags));
+      if (uidmap.find(uid))
+      {
+        // assign the sernum from the cache
+        const ulong sernum = (ulong) uidmap[uid];
+        kdDebug() << "set sernum:" << sernum << " for " << uid << endl;
+        msg->setMsgSerNum(sernum);
+        // delete the entry
+        uidmap.remove(uid);
+      }
+      open();
       KMFolderImapInherited::addMsg(msg, 0);
+      close();
       if (count() > 1) unGetMsg(count() - 1);
       mLastUid = uid;
 /*      if ((*it).total > 20 &&
@@ -967,6 +1003,70 @@ QString KMFolderImap::decodeFileName(con
 }
 
 //-----------------------------------------------------------------------------
+QValueList<int> KMFolderImap::splitSets(QString uids)
+{
+  QValueList<int> uidlist;
+
+  // ex: 1205,1204,1203,1202,1236:1238
+  QString buffer = QString::null;
+  int setstart = -1;
+  // iterate over the uids
+  for (uint i = 0; i < uids.length(); i++)
+  {
+    QChar chr = uids[i];
+    if (chr == ",")
+    {
+      if (setstart > -1)
+      {
+        // a range (uid:uid) was before
+        for (int j = setstart; j <= buffer.toInt(); j++)
+        {
+          uidlist.append(j);
+        }
+        setstart = -1;
+      } else {
+        // single uid
+        uidlist.append(buffer.toInt());
+      }
+      buffer = "";
+    } else if (chr == ":") {
+      // remember the start of the range
+      setstart = buffer.toInt();
+      buffer = "";
+    } else if (chr.category() == QChar::Number_DecimalDigit) {
+      // digit
+      buffer += chr;
+    } else {
+      // ignore
+    }
+  }
+  // process the last data
+  if (setstart > -1)
+  {
+    for (int j = setstart; j <= buffer.toInt(); j++)
+    {
+      uidlist.append(j);
+    }
+  } else {
+    uidlist.append(buffer.toInt());
+  }
+
+  return uidlist;
+}
+
+//-----------------------------------------------------------------------------
+void KMFolderImap::close(bool force)
+{
+  if (mContentState == imapInProgress)
+  {
+    // this folder has some transfer in progress, so we close it later
+    mDeferredClose = TRUE;
+  } else {
+    KMFolderImapInherited::close(force);
+  }
+}
+
+//-----------------------------------------------------------------------------
 KMImapJob::KMImapJob(KMMessage *msg, JobType jt, KMFolderImap* folder)
 {
   mMsg = msg;
@@ -975,13 +1075,16 @@ KMImapJob::KMImapJob(KMMessage *msg, Job
 }
 
 //-----------------------------------------------------------------------------
-KMImapJob::KMImapJob(QPtrList<KMMessage>& msgList, QString sets, JobType jt, \
KMFolderImap* folder) +KMImapJob::KMImapJob(QPtrList<KMMessage>& msgList, QString \
sets,  +    JobType jt, KMFolderImap* folder)
 {
   mMsg = msgList.first();
   init(jt, sets, folder, msgList);
 }
 
-void KMImapJob::init(JobType jt, QString sets, KMFolderImap* folder, \
QPtrList<KMMessage>& msgList) \
+//----------------------------------------------------------------------------- \
+void KMImapJob::init(JobType jt, QString sets, KMFolderImap* folder,  +    \
QPtrList<KMMessage>& msgList)  {
   assert(jt == tGetMessage || folder);
   KMMessage* msg = msgList.first();
@@ -1026,9 +1129,11 @@ void KMImapJob::init(JobType jt, QString
         SLOT(slotPutMessageResult(KIO::Job *)));
     connect(mJob, SIGNAL(dataReq(KIO::Job *, QByteArray &)),
         SLOT(slotPutMessageDataReq(KIO::Job *, QByteArray &)));
+    connect(mJob, SIGNAL(infoMessage(KIO::Job *, const QString &)),
+        SLOT(slotPutMessageInfoData(KIO::Job *, const QString &)));    
     account->displayProgress();
   }
-  else if (jt == tCopyMessage)
+  else if (jt == tCopyMessage || jt == tMoveMessage)
   {
     KURL url = account->getUrl();
     KURL destUrl = account->getUrl();
@@ -1056,6 +1161,11 @@ void KMImapJob::init(JobType jt, QString
     account->mapJobData.insert(mJob, jd);
     connect(mJob, SIGNAL(result(KIO::Job *)),
         SLOT(slotCopyMessageResult(KIO::Job *)));
+    if (jt == tMoveMessage)
+    {
+      connect(mJob, SIGNAL(infoMessage(KIO::Job *, const QString &)),
+          SLOT(slotCopyMessageInfoData(KIO::Job *, const QString &)));    
+    }
     account->displayProgress();
   } else {
     slotGetNextMessage();
@@ -1205,6 +1315,30 @@ void KMImapJob::slotPutMessageResult(KIO
   delete this;
 }
 
+//-----------------------------------------------------------------------------
+void KMImapJob::slotPutMessageInfoData(KIO::Job *job, const QString &data)
+{
+  KMAcctImap *account = mDestFolder->account();
+  QMap<KIO::Job *, KMAcctImap::jobData>::Iterator it =
+    account->mapJobData.find(job);
+  if (it == account->mapJobData.end()) return;
+  if (data.find("UID") != -1)
+  {
+    int uid = (data.right(data.length()-4)).toInt();
+
+    if ( !(*it).msgList.isEmpty() )
+    {
+      const ulong * sernum = (ulong *)(*it).msgList.last()->getMsgSerNum();
+      kdDebug() << "insert sernum " << (*it).msgList.last()->getMsgSerNum() << " for \
" << uid << endl; +      mDestFolder->insertUidSerNumEntry(uid, sernum);
+    } else if (mMsg)
+    {
+      const ulong * sernum = (ulong *)mMsg->getMsgSerNum();
+      kdDebug() << "insert sernum " << mMsg->getMsgSerNum() << " for " << uid << \
endl; +      mDestFolder->insertUidSerNumEntry(uid, sernum);
+    }
+  }
+}
 
 //-----------------------------------------------------------------------------
 void KMImapJob::slotCopyMessageResult(KIO::Job *job)
@@ -1233,6 +1367,51 @@ void KMImapJob::slotCopyMessageResult(KI
   delete this;
 }
 
+//-----------------------------------------------------------------------------
+void KMImapJob::slotCopyMessageInfoData(KIO::Job * job, const QString & data)
+{
+  KMAcctImap *account = mDestFolder->account();
+  QMap<KIO::Job *, KMAcctImap::jobData>::Iterator it =
+    account->mapJobData.find(job);
+  if (it == account->mapJobData.end()) return;
+
+  if (data.find("UID") != -1)
+  {
+    // split
+    QString oldUid = data.section(" ", 1, 1);
+    QString newUid = data.section(" ", 2, 2);
+
+    // get lists of uids
+    QValueList<int> olduids = KMFolderImap::splitSets(oldUid);
+    QValueList<int> newuids = KMFolderImap::splitSets(newUid);
+
+    int index = -1;
+    if ( !(*it).msgList.isEmpty() )
+    {
+      KMMessage * msg;
+      for ( msg = (*it).msgList.first(); msg; msg = (*it).msgList.next() )
+      {
+        uint uid = msg->headerField("X-UID").toInt();
+        index = olduids.findIndex(uid);
+        if (index > -1)
+        {
+          // found, get the new uid
+          const ulong * sernum = (ulong *)msg->getMsgSerNum();
+          mDestFolder->insertUidSerNumEntry(newuids[index], sernum);
+        }
+      }
+    } else if (mMsg) {
+      uint uid = mMsg->headerField("X-UID").toInt();
+      index = olduids.findIndex(uid);
+      if (index > -1)
+      {
+        // found, get the new uid
+        const ulong * sernum = (ulong *)mMsg->getMsgSerNum();
+        mDestFolder->insertUidSerNumEntry(newuids[index], sernum);
+      }
+    }
+  }
+}
 
 //-----------------------------------------------------------------------------
 void KMFolderImap::slotSimpleData(KIO::Job * job, const QByteArray & data)
Index: kdenetwork/kmail/kmfolderimap.h
===================================================================
RCS file: /home/kde/kdenetwork/kmail/kmfolderimap.h,v
retrieving revision 1.31
diff -u -3 -p -r1.31 kmfolderimap.h
--- kdenetwork/kmail/kmfolderimap.h	2002/10/11 22:36:19	1.31
+++ kdenetwork/kmail/kmfolderimap.h	2002/10/14 20:42:43
@@ -31,6 +31,9 @@
 #include "kio/job.h"
 #include "kio/global.h"
 
+#include <qintdict.h>
+#include <qvaluelist.h>
+
 class KMFolderTreeItem;
 class KMFolderImap;
 
@@ -40,7 +43,7 @@ class KMImapJob : public QObject
 
 public:
   enum JobType { tListDirectory, tGetFolder, tCreateFolder, tDeleteMessage,
-    tGetMessage, tPutMessage, tCopyMessage };
+    tGetMessage, tPutMessage, tCopyMessage, tMoveMessage };
   KMImapJob(KMMessage *msg, JobType jt = tGetMessage, KMFolderImap *folder = 0);
   KMImapJob(QPtrList<KMMessage>& msgList, QString sets, JobType jt = tGetMessage, \
KMFolderImap *folder = 0 );  ~KMImapJob();
@@ -57,7 +60,11 @@ private slots:
   /** Feeds the message in pieces to the server */
   void slotPutMessageDataReq(KIO::Job *job, QByteArray &data);
   void slotPutMessageResult(KIO::Job *job);
+  void slotPutMessageInfoData(KIO::Job *, const QString &data);
+  /** result of a copy-operation */
   void slotCopyMessageResult(KIO::Job *job);
+  void slotCopyMessageInfoData(KIO::Job *, const QString &data);
+
 private:
   void init(JobType jt, QString sets, KMFolderImap *folder, QPtrList<KMMessage>& \
msgList);  JobType mType;
@@ -216,6 +223,22 @@ public:
    */
   virtual QString fileName() const { return encodeFileName(name()); }
 
+  /**
+   * Insert a new entry into the uid <=> sernum cache
+   */ 
+  void insertUidSerNumEntry(ulong uid, const ulong * sernum) {
+    uidmap.insert(uid, sernum); }
+
+  /**
+   * Splits a uid-set into single uids
+   */
+  static QValueList<int> splitSets(QString); 
+
+  /**
+   * Reimplemented
+   */
+  virtual void close(bool force=FALSE);  
+
 signals:
   void folderComplete(KMFolderImap *folder, bool success);
 
@@ -332,6 +355,8 @@ protected:
   bool        mCheckFlags;
   bool        mReadOnly;
   QGuardedPtr<KMAcctImap> mAccount;
+  QIntDict<ulong> uidmap;
+  bool        mDeferredClose;
 };
 
 #endif // kmfolderimap_h


_______________________________________________
KMail Developers mailing list
kmail@mail.kde.org
http://mail.kde.org/mailman/listinfo/kmail

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic