# This patch file was generated by NetBeans IDE
# Following Index: paths are relative to: sites/all/modules/scheduler
# This patch can be applied using context Tools: Patch action on respective folder.
# It uses platform neutral UTF-8 encoding and \n newlines.
# Above lines and this line are ignored by the patching process.
Index: scheduler.install
--- scheduler.install Base (BASE)
+++ scheduler.install Locally Modified (Based On LOCAL)
@@ -34,10 +34,28 @@
           'not null' => TRUE,
           'default' => 0,
         ),
+        'perform_publish' => array(
+          'description' => t('Flag indicating publish required'),
+          'type' => 'int',
+          'size' => 'tiny',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+        'perform_unpublish' => array(
+          'description' => t('Flag indicating unpublish required'),
+          'type' => 'int',
+          'size' => 'tiny',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'default' => 0,
+        )
       ),
       'indexes' => array(
         'scheduler_publish_on' => array('publish_on'),
         'scheduler_unpublish_on' => array('unpublish_on'),
+        'scheduler_perform_publish' => array('publish_on', 'perform_publish'),
+        'scheduler_perform_unpublish' => array('unpublish_on', 'perform_unpublish'),
       ),
       'primary key' => array('nid'),
     ),
@@ -83,3 +101,50 @@
   }
   return $ret;
 }
+
+/**
+ * Add fields and indexes indicating whether (un)publish needs to be performed.
+ *
+ * Added to support history of scheduled actions and in turn entering dates in
+ * the past.
+ */
+function scheduler_update_6101() {
+  $ret = array();
+
+  // Field added to indicate publish needs to be performed.
+  $new_field = array(
+    'description' => t('Flag indicating publish required'),
+    'type' => 'int',
+    'size' => 'tiny',
+    'unsigned' => TRUE,
+    'not null' => TRUE,
+    'default' => 0,
+  );
+  // Index added to speed querying in scheduler_cron().
+  $new_index = array('indexes' => array(
+    'scheduler_perform_publish' => array('publish_on', 'perform_publish'),
+  ));
+  db_add_field($ret, 'scheduler', 'perform_publish', $new_field, $new_index);
+
+  // Field added to indicate publish needs to be performed.
+  $new_field = array(
+    'description' => t('Flag indicating unpublish required'),
+    'type' => 'int',
+    'size' => 'tiny',
+    'unsigned' => TRUE,
+    'not null' => TRUE,
+    'default' => 0,
+  );
+  $new_index = array('indexes' => array(
+    'scheduler_perform_ubpublish' => array('unpublish_on', 'perform_unpublish'),
+  ));
+  db_add_field($ret, 'scheduler', 'perform_unpublish', $new_field, $new_index);
+
+  // Set perform flag 1 to any non-zero values as they will not get fixed
+  // by Cron - db_query() used since drupal_write_record() is not available in
+  // hook_update() as it does not know about the schema change.
+  db_query('UPDATE {scheduler} SET perform_publish = %d WHERE publish_on > %d', 1, 0);
+  db_query('UPDATE {scheduler} SET perform_unpublish = %d WHERE unpublish_on > %d', 1, 0);
+
+  return $ret;
+}
Index: scheduler.module
--- scheduler.module Base (BASE)
+++ scheduler.module Locally Modified (Based On LOCAL)
@@ -112,6 +112,12 @@
       '#default_value' => variable_get('scheduler_touch_'. $form['#node_type']->type, 0),
       '#description' => t('Check this box to alter the published on time to match the scheduled time ("touch feature").')
     );
+    $form['workflow']['scheduler_history'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Allow scheduled dates in the past'),
+      '#default_value' => variable_get('scheduler_history_'. $form['#node_type']->type, 0),
+      '#description' => t('Check this box to allow setting scheduled dates in the past.')
+    );
   }
 
   // is this a node form?
@@ -386,68 +392,122 @@
         // because DRUPAL6 removed 'submit' and added 'presave'
         // and all this happens at different times.
 
+        // Init $now to provide consistent logic throughout case
+        $now = time();
         $date_format = variable_get('scheduler_date_format', SCHEDULER_DATE_FORMAT);
+        // Initialize perform_publish and perform_unpublish to 0
+        $node->perform_publish = $node->perform_unpublish = 0;
 
+        // Set publish values
         if (isset($node->publish_on) && $node->publish_on && !is_numeric($node->publish_on)) {
           $publishtime = _scheduler_strtotime($node->publish_on);
+          // If bad time format provided
           if ($publishtime === FALSE) {
             form_set_error('publish_on', t("The 'publish on' value does not match the expected format of %time", array('%time' => format_date(time(), 'custom', $date_format))));
           }
-          elseif ($publishtime && $publishtime < time()) {
+          // Else if publish time is in the past and history is not enabled
+          elseif (!variable_get('scheduler_history_' . $node->type, 0)
+                  && $publishtime < $now) {
             form_set_error('publish_on', t("The 'publish on' date must be in the future"));
           }
+          // Else publish time is acceptable
           else {
             $node->publish_on = $publishtime;
+            if ($node->publish_on >= $now) {
+              $node->perform_publish = 1;
+            }
           }
         }
 
+        // Set unpublish values
         if (isset($node->unpublish_on) && $node->unpublish_on && !is_numeric($node->unpublish_on)) {
           $unpublishtime = _scheduler_strtotime($node->unpublish_on);
+          // If bad time format provided
           if ($unpublishtime === FALSE) {
             form_set_error('unpublish_on', t("The 'unpublish on' value does not match the expected format of %time", array('%time' => format_date(time(), 'custom', $date_format))));
           }
-          elseif ($unpublishtime && $unpublishtime < time()) {
+          // Else if unpublish time is in the past and history is not enabled
+          elseif (!variable_get('scheduler_history_' . $node->type, 0)
+                  && $unpublishtime < $now) {
             form_set_error('unpublish_on', t("The 'unpublish on' date must be in the future"));
           }
+          // Else unpublish time is acceptable
           else {
             $node->unpublish_on = $unpublishtime;
+            if ($node->unpublish_on >= $now) {
+              $node->perform_unpublish = 1;
+            }
           }
         }
 
+        // Ensure publish time is greater than unpublish time if both are set.
         if (isset($publishtime) && isset($unpublishtime) && $unpublishtime < $publishtime) {
           form_set_error('unpublish_on', t("The 'unpublish on' date must be later than the 'publish on' date."));
         }
 
-        // Right before we save the node, we need to check if a "publish on" value has been set.
-        // If it has been set, we want to make sure the node is unpublished since it will be published at a later date
-        if (isset($node->publish_on) && $node->publish_on != '' && is_numeric($node->publish_on) && $node->publish_on > time()) {
+        // If publish is scheduled
+        if ($node->perform_publish) {
+          // Then unpublish as the publish date is not yet reached
           $node->status = 0;
         }
+        // Elseif unpublish is scheduled
+        elseif ($node->perform_unpublish) {
+          // Then publish as publish_on was not set or occurred in the past
+          $node->status = 1;
+        }
+        // Elseif unpublish has been set
+        elseif (isset($node->unpublish_on) && !empty($node->unpublish_on)
+                && is_numeric($node->unpublish_on)) {
+          // Then unpublish occurred in the past, so unpublish
+          $node->status = 0;
+        }
+        // Elseif publish has been set
+        elseif (isset($node->publish_on) && !empty($node->publish_on)
+                && is_numeric($node->publish_on)) {
+          // Then publish as it occurred in the past and unpublish not scheduled
+          $node->status = 1;
+        }
+        // Else nothing done to publish status
         break;
       case 'insert':
-        // only insert into database if we need to (un)publish this node at some date
+        // Insert into database if we need to (un)publish this node at some date
         if (isset($node->nid) && $node->nid && (isset($node->publish_on) && $node->publish_on != NULL) || (isset($node->unpublish_on) && $node->unpublish_on != NULL)) {
-          db_query('INSERT INTO {scheduler} (nid, publish_on, unpublish_on) VALUES (%d, %d, %d)', $node->nid, $node->publish_on, $node->unpublish_on);
+          drupal_write_record('scheduler', $node);
         }
         break;
       case 'update':
         if (isset($node->nid) && $node->nid) {
           $exists = db_result(db_query('SELECT nid FROM {scheduler} WHERE nid = %d', $node->nid));
 
-          // if this node has already been scheduled, update its record
+          // If this node has already been scheduled, update its record
           if ($exists) {
-            // only update database if we need to (un)publish this node at some date
-            // otherwise the user probably cleared out the (un)publish dates so we should remove the record
-            if (($node->status == 0 && isset($node->publish_on) && $node->publish_on != NULL) || (isset($node->unpublish_on) && $node->unpublish_on != NULL)) {
-              db_query('UPDATE {scheduler} SET publish_on = %d, unpublish_on = %d WHERE nid = %d', $node->publish_on, $node->unpublish_on, $node->nid);
+            // If (un)publish not set then set to 0, fixes problem where if the
+            // user manually clears a previously set (un)publish_on the
+            // scheduled field is not cleared in drupal_write_record().
+            if (!isset($node->publish_on)) {
+              $node->publish_on = 0;
             }
+            if (!isset($node->unpublish_on)) {
+              $node->unpublish_on = 0;
+            }
+
+            // If (un)publish needed at some date in the future
+            if ($node->perform_publish || $node->perform_unpublish) {
+              drupal_write_record('scheduler', $node, 'nid');
+            }
+            // Else if history is enabled and (un)publish is set
+            elseif (variable_get('scheduler_history_' . $node->type, 0) &&
+                    $node->publish_on || $node->unpublish_on) {
+              drupal_write_record('scheduler', $node, 'nid');
+            }
+            // Else remove record, if any to be removed
             else {
               db_query('DELETE FROM {scheduler} WHERE nid = %d', $node->nid);
             }
           }
-          // node doesn't exist, create a record only if the (un)publish fields are blank
+          // Else if node not scheduled create a record if (un)publish set
           elseif ((isset($node->publish_on) && $node->publish_on != NULL) || (isset($node->unpublish_on) && $node->unpublish_on != NULL)) {
-            db_query('INSERT INTO {scheduler} (nid, publish_on, unpublish_on) VALUES (%d, %d, %d)', $node->nid, $node->publish_on, $node->unpublish_on);
+            drupal_write_record('scheduler', $node);
           }
         }
         break;
@@ -466,8 +526,16 @@
 function scheduler_cron() {
   $clear_cache = FALSE;
 
-  // if the time now is greater than the time to publish a node, publish it
-  $nodes = db_query('SELECT * FROM {scheduler} s LEFT JOIN {node} n ON s.nid = n.nid WHERE n.status = 0 AND s.publish_on > 0 AND s.publish_on < %d ', time());
+  // If the time now is greater than the time to publish a node and is
+  // flagged to be published
+  $nodes = db_query('
+    SELECT *
+    FROM {scheduler} s
+    LEFT JOIN {node} n ON s.nid = n.nid
+    WHERE s.publish_on > 0
+      AND s.publish_on < %d
+      AND s.perform_publish = 1
+  ', time());
 
   while ($node = db_fetch_object($nodes)) {
     $n = node_load($node->nid);
@@ -482,11 +550,16 @@
     $context['node'] = $n;
     actions_do($actions, $n, $context, NULL, NULL);
 
-    // if this node is not to be unpublished, then we can delete the record
-    if (isset($n->unpublish_on) && $n->unpublish_on == 0) {
+    // If the node's type has the history option enabled
+    if (variable_get('scheduler_history_' . $n->type, 0)) {
+      $node->perform_publish = 0;
+      drupal_write_record('scheduler', $node, 'nid');
+    }
+    // Elseif this node is not to be unpublished, then we can delete the record
+    elseif (isset($n->unpublish_on) && $n->unpublish_on == 0) {
       db_query('DELETE FROM {scheduler} WHERE nid = %d', $n->nid);
     }
-    // we need to unpublish this node at some time so clear the publish on since it's been published
+    // Else we need to unpublish this node at some time so clear the publish on since it's been published
     else {
       db_query('UPDATE {scheduler} SET publish_on = 0 WHERE nid = %d', $n->nid);
     }
@@ -497,8 +570,16 @@
     $clear_cache = TRUE;
   }
 
-  // if the time is greater than the time to unpublish a node, unpublish it
-  $nodes = db_query('SELECT * FROM {scheduler} s LEFT JOIN {node} n ON s.nid = n.nid WHERE n.status = 1 AND s.unpublish_on > 0 AND s.unpublish_on < %d', time());
+  // Select records where the time now is greater than the time to unpublish a
+  // node and is flagged to be unpublished
+  $nodes = db_query('
+    SELECT *
+    FROM {scheduler} s
+    LEFT JOIN {node} n ON s.nid = n.nid
+    WHERE s.unpublish_on > 0
+      AND s.unpublish_on < %d
+      AND s.perform_unpublish = 1
+  ', time());
 
   while ($node = db_fetch_object($nodes)) {
     // if this node is to be unpublished, we can update the node and remove the record since it can't be republished
@@ -510,8 +591,17 @@
     $actions = array('node_unpublish_action', 'node_save_action');
     $context['node'] = $n;
     actions_do($actions, $n, $context, NULL, NULL);
-    db_query('DELETE FROM {scheduler} WHERE nid = %d', $n->nid);
 
+    // If the node's type has the history option enabled
+    if (variable_get('scheduler_history_' . $n->type, 0)) {
+      $node->perform_unpublish = 0;
+      drupal_write_record('scheduler', $node, 'nid');
+    }
+    // Else remove the record
+    else {
+      db_query('DELETE FROM {scheduler} WHERE nid = %d', $n->nid);
+    }
+
     // invoke scheduler API
     _scheduler_scheduler_api($n, 'unpublish');
 
