Update of /cvsroot/mahogany/M/src/modules
In directory sc8-pr-cvs1:/tmp/cvs-serv10991/src/modules

Modified Files:
        Filters.cpp 
Log Message:
patch from Robert to avoid losing messages when opening the target folder was cancelled

Index: Filters.cpp
===================================================================
RCS file: /cvsroot/mahogany/M/src/modules/Filters.cpp,v
retrieving revision 1.147
retrieving revision 1.148
diff -b -u -2 -r1.147 -r1.148
--- Filters.cpp 22 Jul 2003 22:01:42 -0000      1.147
+++ Filters.cpp 3 Aug 2003 23:55:19 -0000       1.148
@@ -95,4 +95,5 @@
 class Token;
 class Value;
+class FilterRuleApply;
 
 /// Type for functions to be called.
@@ -335,4 +336,6 @@
         m_hasHeaderFunc;
 
+   friend class FilterRuleApply;
+
    GCC_DTOR_WARN_OFF
 };
@@ -431,5 +434,5 @@
    // Can't use union here because m_String needs constructor.
    long   m_Num;
-   const String m_String;
+   String m_String;
 
    // if this flag is set, it means that the filter evaluation must be aborted
@@ -437,10 +440,57 @@
    bool m_abort;
 
-   // not needed nor implemented for now
-   Value& operator=(const Value&);
-
    MOBJECT_NAME(Value)
 };
 
+// an object of this class is created to apply the given rule to the specified
+// messages, it is a sort of "filter runner"
+class FilterRuleApply
+{
+public:
+   FilterRuleApply(FilterRuleImpl *parent, UIdArray& msgs);
+   ~FilterRuleApply();
+
+   int Run();
+
+private:
+   bool LoopEvaluate();
+   bool LoopCopy();
+   bool DeleteAll();
+
+   void CreateProgressDialog();
+   bool GetMessage();
+   bool UpdateProgressDialog();
+   void HeaderCacheHints();
+   bool Evaluate();
+   bool ProgressResults();
+   bool ProgressCopy();
+   bool CopyToOneFolder();
+   void CollectForDelete();
+   void ProgressDelete();
+   void IndicateDeleted();
+
+   FilterRuleImpl *const m_parent;
+   UIdArray& m_msgs;
+
+   MProgressDialog *m_pd;
+   wxArrayInt m_allOperations;
+   wxArrayString m_destinations;
+   bool m_doExpunge;
+   UIdArray m_uidsToDelete;
+
+   // the array holding the indices of the messages deleted by filters
+   wxArrayLong m_indicesDeleted;
+
+   // Index of actual message in m_messageList
+   size_t m_idx;
+
+   // the text for the progress dialog (verbose) and for the log (terse)
+   String m_textPD,
+          m_textLog;
+
+   // Result of evaluating filter
+   Value m_retval;
+};
+
 // ----------------------------------------------------------------------------
 // ABC for syntax tree nodes.
@@ -3071,5 +3121,4 @@
 // ----------------------------------------------------------------------------
 
-// TODO: this function should be factorized into several smaller ones
 int
 FilterRuleImpl::Apply(MailFolder *mf, UIdArray& msgs)
@@ -3089,23 +3138,224 @@
       m_MailFolder->IncRef();
 
-      // the array holding the indices of the messages deleted by filters
-      wxArrayLong indicesDeleted;
+      FilterRuleApply apply(this, msgs);
+
+      rc = apply.Run();
+
+      m_MailFolder->DecRef();
+      m_MailFolder = NULL;
+   }
+#endif // !TEST
+
+   return rc;
+}
+
+FilterRuleImpl::FilterRuleImpl(const String &filterrule,
+                               MInterface *minterface,
+                               MModule_Filters *mod)
+              : m_FilterModule(mod),
+                m_MInterface(minterface)
+{
+#ifndef TEST
+   // we cannot allow the module to disappear while we exist
+   m_FilterModule->IncRef();
+#endif
+
+   m_hasToFunc =
+   m_hasRcptFunc =
+   m_hasHdrLineFunc =
+   m_hasHeaderFunc = false;
+
+   m_Program = Parse(filterrule);
+   m_MessageUId = UID_ILLEGAL;
+   m_MailMessage = NULL;
+   m_MailFolder = NULL;
+}
+
+FilterRuleImpl::~FilterRuleImpl()
+{
+   SafeDecRef(m_MailFolder);
+   delete m_Program;
+#ifndef TEST
+   m_FilterModule->DecRef();
+#endif
+}
+
+#ifdef DEBUG
+
+void FilterRuleImpl::Debug(void)
+{
+   Output(m_Program->Debug());
+}
+
+#endif // DEBUG
+
+// ----------------------------------------------------------------------------
+// FilterRuleApply
+// ----------------------------------------------------------------------------
+
+FilterRuleApply::FilterRuleApply(FilterRuleImpl *parent, UIdArray& msgs)
+               : m_parent(parent), m_msgs(msgs)
+{
+   m_pd = NULL;
+   m_doExpunge = false;
+}
+
+FilterRuleApply::~FilterRuleApply()
+{
+   delete m_pd;
+}
+
+int
+FilterRuleApply::Run()
+{
+   // no error yet
+   int rc = 0;
+
+   CreateProgressDialog();
+
+   if( !LoopEvaluate() )
+   {
+      rc |= FilterRule::Error;
+   }
+
+   // check if Cancel wasn't pressed (we'd exit the loop above by break then)
+   if ( m_idx == m_msgs.GetCount() &&
+        (!m_pd || m_pd->Update(m_msgs.GetCount(),
+        _("Executing filter actions..."))) )
+   {
+      if ( !LoopCopy() )
+      {
+         rc |= FilterRule::Error;
+      }
+
+      // again, stop right now if we were cancelled
+      if ( m_idx == m_msgs.GetCount() )
+      {
+         if ( !DeleteAll() )
+         {
+            rc |= FilterRule::Error;
+         }
+         else // deleted successfully
+         {
+            rc |= FilterRule::Deleted;
+         }
+
+         // actual expunging will be done by the calling code
+         if ( m_doExpunge )
+         {
+            rc |= FilterRule::Expunged;
+         }
+      }
+   }
+   //else: cancelled by user
+
+   return rc;
+}
+
+bool
+FilterRuleApply::LoopEvaluate()
+{
+   bool allOk = true;
+
+   // first decide what should we do with the messages: fill the arrays with
+   // the operations to perform and the destination folder if the operation
+   // involves copying the message
+   for ( m_idx = 0; m_idx < m_msgs.GetCount(); m_idx++ )
+   {
+      // do it first so that the arrays have the right size even if we hit
+      // "continue" below
+      m_allOperations.Add(FilterRuleImpl::None);
+      m_destinations.Add("");
+
+      if ( !GetMessage() )
+      {
+         continue;
+      }
+
+      if ( !UpdateProgressDialog() )
+      {
+         m_parent->m_MailMessage->DecRef();
+
+         break;
+      }
+
+      HeaderCacheHints();
+
+      if ( !Evaluate() )
+      {
+         allOk = false;
+      }
+
+      if ( !ProgressResults() )
+      {
+         break;
+      }
+   }
+
+   return allOk;
+}
+
+bool
+FilterRuleApply::LoopCopy()
+{
+   bool allOk = true;
+
+   for ( m_idx = 0; m_idx < m_msgs.GetCount(); m_idx++ )
+   {
+      if ( m_allOperations[m_idx] & FilterRuleImpl::Copy )
+      {
+         if ( !ProgressCopy() )
+         {
+            // cancelled by user
+            break;
+         }
+
+         if ( !CopyToOneFolder() )
+         {
+            allOk = false;
+         }
+      }
+   }
+
+   return allOk;
+}
+
+bool
+FilterRuleApply::DeleteAll()
+{
+   CollectForDelete();
+
+   if ( !m_uidsToDelete.IsEmpty() )
+   {
+      ProgressDelete();
+
+      if ( !m_parent->m_MailFolder->DeleteMessages(&m_uidsToDelete) )
+      {
+         return false;
+      }
+
+      // deleted successfully
+      IndicateDeleted();
+   }
 
-      // show the progress dialog while filtering
-      size_t count = msgs.GetCount();
+   return true;
+}
 
-      wxFrame *frame = m_MailFolder->GetInteractiveFrame();
-      MProgressDialog *pd;
+void
+FilterRuleApply::CreateProgressDialog()
+{
+   wxFrame *frame = m_parent->m_MailFolder->GetInteractiveFrame();
       if ( frame )
       {
-         pd = new MProgressDialog
+      m_pd = new MProgressDialog
                   (
                      wxString::Format
                      (
                         _("Filtering %u messages in folder '%s'..."),
-                        count, m_MailFolder->GetName().c_str()
+                     m_msgs.GetCount(),
+                     m_parent->m_MailFolder->GetName().c_str()
                      ),
                      "\n\n",  // must be tall enough for 3 lines
-                     2*count,
+                  2*m_msgs.GetCount(),
                      frame,
                      false,   // !"disable parent only"
@@ -3113,48 +3363,38 @@
                   );
       }
-      else // don't show the progress dialog, just log in the status bar
-      {
-         pd = NULL;
-      }
-
-      // first decide what should we do with the messages: fill the arrays with
-      // the operations to perform and the destination folder if the operation
-      // involves copying the message
-      wxArrayInt operations;
-      wxArrayString destinations;
-
-      bool doExpunge = false;
-
-      // the text for the progress dialog (verbose) and for the log (terse)
-      String textPD,
-             textLog;
-      size_t idx;
-      for ( idx = 0; idx < count; idx++ )
-      {
-         // do it first so that the arrays have the right size even if we hit
-         // "continue" below
-         operations.Add(None);
-         destinations.Add("");
+   // else: don't show the progress dialog, just log in the status bar
+}
 
-         m_MessageUId = msgs[idx];
+bool
+FilterRuleApply::GetMessage()
+{
+   m_parent->m_MessageUId = m_msgs[m_idx];
 
-         if ( m_MessageUId == UID_ILLEGAL )
+   if ( m_parent->m_MessageUId == UID_ILLEGAL )
          {
             FAIL_MSG( _T("invalid UID in FilterRule::Apply()!") );
 
-            continue;
+      return false;
          }
 
-         m_MailMessage = m_MailFolder->GetMessage(m_MessageUId);
+   m_parent->m_MailMessage
+      = m_parent->m_MailFolder->GetMessage(m_parent->m_MessageUId);
 
-         if ( !m_MailMessage )
+   if ( !m_parent->m_MailMessage )
          {
             // maybe another session deleted it?
             wxLogDebug(
                _T("Filter error: message with UID %ld in folder '%s' doesn't exist 
any more."),
-                       m_MessageUId, m_MailFolder->GetName().c_str());
-            continue;
+                 m_parent->m_MessageUId,
+                 m_parent->m_MailFolder->GetName().c_str());
+      return false;
          }
 
+   return true;
+}
+
+bool
+FilterRuleApply::UpdateProgressDialog()
+{
          // update the GUI
 
@@ -3162,46 +3402,46 @@
          //       configurable
 
-         String subject = MailFolder::DecodeHeader(m_MailMessage->Subject()),
-                from = MailFolder::DecodeHeader(m_MailMessage->From());
+   String subject = MailFolder::DecodeHeader(
+      m_parent->m_MailMessage->Subject());
+   String from = MailFolder::DecodeHeader(m_parent->m_MailMessage->From());
 
-         textLog.Printf(_("Filtering message %u/%u"), idx + 1, count);
+   m_textLog.Printf(_("Filtering message %u/%u"),
+      m_idx + 1, m_msgs.GetCount());
 
          // make a multiline label for the progress dialog and a more concise
          // one for the status bar
-         if ( pd )
+   m_textPD.clear();
+   if ( m_pd )
          {
-            textPD.clear();
-            textPD << textLog << '\n'
+      m_textPD << m_textLog << '\n'
                    << _("From: ") << from << '\n'
                    << _("Subject: ") << subject;
          }
 
-         textLog << " (";
+   m_textLog << " (";
 
          if ( !from.empty() )
          {
-            textLog << _("from ") << from << ' ';
+      m_textLog << _("from ") << from << ' ';
          }
 
          if ( !subject.empty() )
          {
-            textLog << _("about '") << subject << '\'';
+      m_textLog << _("about '") << subject << '\'';
          }
          else
          {
-            textLog << _("without subject");
+      m_textLog << _("without subject");
          }
 
-         textLog << ')';
+   m_textLog << ')';
 
          // and use both of them
-         if ( pd )
+   if ( m_pd )
          {
-            if ( !pd->Update(idx, textPD) )
+      if ( !m_pd->Update(m_idx, m_textPD) )
             {
                // cancelled by user
-               m_MailMessage->DecRef();
-
-               break;
+         return false;
             }
          }
@@ -3210,7 +3450,13 @@
             // don't pass it as the first argument because the string might
             // contain '%' characters!
-            wxLogStatus("%s", textLog.c_str());
+      wxLogStatus("%s", m_textLog.c_str());
          }
 
+   return true;
+}
+
+void
+FilterRuleApply::HeaderCacheHints()
+{
          // do some heuristic optimizations: if our program contains requests
          // for the entire message header, get it first because like this it
@@ -3221,43 +3467,54 @@
          // in the same way, retrieve all the recipients if we need them anyhow
          // before retrieving "To" &c
-         if ( m_hasHeaderFunc )
+   if ( m_parent->m_hasHeaderFunc )
          {
-            if ( m_hasToFunc || m_hasRcptFunc || m_hasHdrLineFunc )
+      if ( m_parent->m_hasToFunc || m_parent->m_hasRcptFunc
+         || m_parent->m_hasHdrLineFunc )
             {
                // pre-retrieve the whole header
-               (void)m_MailMessage->GetHeader();
+         (void)m_parent->m_MailMessage->GetHeader();
             }
          }
-         else if ( m_hasRcptFunc )
+   else if ( m_parent->m_hasRcptFunc )
          {
-            if ( m_hasToFunc )
+      if ( m_parent->m_hasToFunc )
             {
                // pre-fetch the recipient headers which include "To"
-               (void)m_MailMessage->GetHeaderLines(headersRecipients);
+         (void)m_parent->m_MailMessage->GetHeaderLines(headersRecipients);
             }
          }
+}
 
+bool
+FilterRuleApply::Evaluate()
+{
          // reset the result flags
-         m_operation = None;
+   m_parent->m_operation = FilterRuleImpl::None;
 
-         const Value retval = m_Program->Evaluate();
+   m_retval = m_parent->m_Program->Evaluate();
 
          // remember the result
-         operations[idx] = m_operation;
-         destinations[idx] = m_copiedTo;
+   m_allOperations[m_idx] = m_parent->m_operation;
+   m_destinations[m_idx] = m_parent->m_copiedTo;
 
-         if ( m_operation & Expunge )
+   if ( m_parent->m_operation & FilterRuleImpl::Expunge )
          {
-            doExpunge = true;
+      m_doExpunge = true;
          }
 
+   m_parent->m_MailMessage->DecRef();
+
+   return m_retval.IsNumber();
+}
+
+bool
+FilterRuleApply::ProgressResults()
+{
          // and show the result in the progress dialog
          String textExtra = " - ";
 
-         if ( !retval.IsNumber() )
+   if ( !m_retval.IsNumber() )
          {
             textExtra << _("error!");
-
-            rc |= FilterRule::Error;
          }
          else // filter executed ok
@@ -3274,11 +3531,12 @@
             }
 
-            bool wasDeleted = (m_operation & Deleted) != 0;
-            if ( !m_copiedTo.empty() )
+      bool wasDeleted = (m_parent->m_operation
+         & FilterRuleImpl::Deleted) != 0;
+      if ( !m_parent->m_copiedTo.empty() )
             {
                textExtra << (wasDeleted ? _("moved to ") : _("copied to "))
-                         << m_copiedTo;
+                   << m_parent->m_copiedTo;
 
-               m_copiedTo.clear();
+         m_parent->m_copiedTo.clear();
             }
             else if ( wasDeleted )
@@ -3292,14 +3550,12 @@
          }
 
-         textLog += textExtra;
-
-         m_MailMessage->DecRef();
+   m_textLog += textExtra;
 
-         if ( pd )
+   if ( m_pd )
          {
-            if ( !pd->Update(idx, textPD + textExtra) )
+      if ( !m_pd->Update(m_idx, m_textPD + textExtra) )
             {
                // cancelled by user
-               break;
+         return false;
             }
 
@@ -3309,23 +3565,18 @@
             // NB: textLog may contain '%'s itself, so don't let it be
             //     interpreted as a format string
-            wxLogGeneric(M_LOG_WINONLY, "%s", textLog.c_str());
+      wxLogGeneric(M_LOG_WINONLY, "%s", m_textLog.c_str());
          }
          else // no progress dialog
          {
             // see comment above
-            wxLogStatus("%s", textLog.c_str());
-         }
+      wxLogStatus("%s", m_textLog.c_str());
       }
 
-      // check if Cancel wasn't pressed (we'd exit the loop above by break then)
-      wxString pdExecText = _("Executing filter actions...");
-      if ( idx == count &&
-           (!pd || pd->Update(count, pdExecText)) )
-      {
-         UIdArray uidsToDelete;
-         wxArrayLong indicesDeleted;
+   return true;
+}
 
-         for ( idx = 0; idx < count; idx++ )
-         {
+bool
+FilterRuleApply::ProgressCopy()
+{
             // note that our progress meter may accelerate towards the end as
             // we may copy more than one message initially - but it's ok, it's
@@ -3333,127 +3584,95 @@
             // this!
 
-            if ( pd && !pd->Update(count + idx) )
+   if ( m_pd )
             {
-               // cancelled by user
-               break;
-            }
+      wxString message = _("Executing filter actions...") + '\n'
+         + wxString::Format(_("Copying messages to '%s'..."),
+            m_destinations[m_idx].c_str());
 
-            if ( operations[idx] & Copy )
+      if( !m_pd->Update(m_msgs.GetCount() + m_idx, message) )
             {
+         return false;
+      }
+   }
+
+   return true;
+}
+
+bool
+FilterRuleApply::CopyToOneFolder()
+{
                // copy all messages we are copying to this destination at once
                UIdArray uidsToCopy;
-               uidsToCopy.Add(msgs[idx]);
+   wxArrayLong indexesToCopy;
 
-               String dst = destinations[idx];
+   uidsToCopy.Add(m_msgs[m_idx]);
+   indexesToCopy.Add(m_idx);
 
-               for ( size_t n = idx + 1; n < count; n++ )
+   for ( size_t n = m_idx + 1; n < m_msgs.GetCount(); n++ )
                {
-                  if ( (operations[n] & Copy) && destinations[n] == dst )
+      if ( (m_allOperations[n] & FilterRuleImpl::Copy)
+         && m_destinations[n] == m_destinations[m_idx] )
                   {
-                     uidsToCopy.Add(msgs[n]);
-
-                     // don't try to copy it when we reach it
-                     operations[n] &= ~Copy;
+         uidsToCopy.Add(m_msgs[n]);
+         indexesToCopy.Add(n);
                   }
                }
 
-               if ( pd )
-               {
-                  pd->Update(count + idx, pdExecText + '\n' +
-                             wxString::Format(_("Copying messages to '%s'..."),
-                                           dst.c_str()));
-               }
+   bool copyOk = m_parent->m_MailFolder->SaveMessages(
+      &uidsToCopy, m_destinations[m_idx]);
 
-               if ( !m_MailFolder->SaveMessages(&uidsToCopy, dst) )
+   for ( size_t copiedIndex = 0; copiedIndex < indexesToCopy.GetCount();
+      ++copiedIndex )
                {
-                  rc |= FilterRule::Error;
-               }
-            }
+      // don't try to copy it when we reach it
+      m_allOperations[copiedIndex] &= ~FilterRuleImpl::Copy;
 
-            if ( operations[idx] & Delete )
+      if ( !copyOk )
             {
-               indicesDeleted.Add(idx);
-               uidsToDelete.Add(msgs[idx]);
+         m_allOperations[copiedIndex] &= ~FilterRuleImpl::Delete;
             }
          }
 
-         // again, stop right now if we were cancelled
-         if ( idx == count )
-         {
-            if ( !uidsToDelete.IsEmpty() )
+   return copyOk;
+}
+
+void
+FilterRuleApply::CollectForDelete()
+{
+   m_uidsToDelete.Empty();
+   m_indicesDeleted.Empty();
+
+   for ( m_idx = 0; m_idx < m_msgs.GetCount(); m_idx++ )
             {
-               if ( pd )
+      if ( m_allOperations[m_idx] & FilterRuleImpl::Delete )
                {
-                  pd->Update(2*count, pdExecText + '\n' +
-                            wxString::Format(_("Deleting moved messages...")));
+         m_indicesDeleted.Add(m_idx);
+         m_uidsToDelete.Add(m_msgs[m_idx]);
+      }
                }
+}
 
-               if ( !m_MailFolder->DeleteMessages(&uidsToDelete) )
+void
+FilterRuleApply::ProgressDelete()
+{
+   if ( m_pd )
                {
-                  rc |= FilterRule::Error;
+      m_pd->Update(2*m_msgs.GetCount(),
+         String(_("Executing filter actions...")) + '\n'
+         + _("Deleting moved messages..."));
                }
-               else // deleted successfully
-               {
-                  rc |= FilterRule::Deleted;
+}
 
+void
+FilterRuleApply::IndicateDeleted()
+{
                   // remove the deleted messages from msgs
                   // iterate from end because otherwise the indices would shift
                   // while we traverse them
-                  size_t count = indicesDeleted.GetCount();
+   size_t count = m_indicesDeleted.GetCount();
                   for ( size_t n = count; n > 0; n-- )
                   {
-                     msgs.RemoveAt(indicesDeleted[n - 1]);
-                  }
-               }
-            }
-
-            // actual expunging will be done by the calling code
-            if ( doExpunge )
-            {
-               rc |= FilterRule::Expunged;
-            }
+      m_msgs.RemoveAt(m_indicesDeleted[n - 1]);
          }
-      }
-      //else: cancelled by user
-
-      delete pd;
-
-      m_MailFolder->DecRef();
-      m_MailFolder = NULL;
-   }
-#endif // !TEST
-
-   return rc;
-}
-
-FilterRuleImpl::FilterRuleImpl(const String &filterrule,
-                               MInterface *minterface,
-                               MModule_Filters *mod)
-              : m_FilterModule(mod),
-                m_MInterface(minterface)
-{
-#ifndef TEST
-   // we cannot allow the module to disappear while we exist
-   m_FilterModule->IncRef();
-#endif
-
-   m_hasToFunc =
-   m_hasRcptFunc =
-   m_hasHdrLineFunc =
-   m_hasHeaderFunc = false;
-
-   m_Program = Parse(filterrule);
-   m_MessageUId = UID_ILLEGAL;
-   m_MailMessage = NULL;
-   m_MailFolder = NULL;
-}
-
-FilterRuleImpl::~FilterRuleImpl()
-{
-   SafeDecRef(m_MailFolder);
-   delete m_Program;
-#ifndef TEST
-   m_FilterModule->DecRef();
-#endif
 }
 
@@ -3461,11 +3680,4 @@
 // MModule_FiltersImpl - the module
 // ----------------------------------------------------------------------------
-
-#ifdef DEBUG
-void FilterRuleImpl::Debug(void)
-{
-   Output(m_Program->Debug());
-}
-#endif
 
 /** Filtering Module class. */



-------------------------------------------------------
This SF.Net email sponsored by: Free pre-built ASP.NET sites including
Data Reports, E-commerce, Portals, and Forums are available now.
Download today and enter to win an XBOX or Visual Studio .NET.
http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01
_______________________________________________
Mahogany-cvsupdates mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/mahogany-cvsupdates

Reply via email to