Index: subscriptions.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/subscriptions/subscriptions.module,v
retrieving revision 1.88
diff -u -r1.88 subscriptions.module
--- subscriptions.module	20 Jul 2009 21:22:21 -0000	1.88
+++ subscriptions.module	22 Aug 2009 02:32:21 -0000
@@ -244,6 +244,7 @@
     case 'delete':
       db_query("DELETE FROM {subscriptions_user} WHERE uid = %d", $account->uid);
       db_query("DELETE FROM {subscriptions} WHERE recipient_uid = %d", $account->uid);
+      db_query("DELETE FROM {subscriptions_last_sent} WHERE uid = %d", $account->uid);
       break;
   }
 }
@@ -325,11 +326,12 @@
         $conditions = implode(' AND ', $where);
         $sql = "
           INSERT INTO {subscriptions_queue} (uid, name, mail, language, module, field, value, author_uid, send_interval, digest, last_sent, load_function, load_args, is_new)
-          SELECT u.uid, u.name, u.mail, u.language, s.module, s.field, s.value, s.author_uid, s.send_interval, su.digest, su.last_sent, '%s', '%s', '%d'
+          SELECT u.uid, u.name, u.mail, u.language, s.module, s.field, s.value, s.author_uid, s.send_interval, su.digest, COALESCE(sls.last_sent, 0), '%s', '%s', '%d'
           FROM {subscriptions} s
           INNER JOIN {subscriptions_user} su ON s.recipient_uid = su.uid
           INNER JOIN {users} u ON su.uid = u.uid
           $join
+          LEFT JOIN {subscriptions_last_sent} sls ON su.uid = sls.uid AND s.send_interval = sls.send_interval
           WHERE
             s.module = '%s' AND
             s.field = '%s' AND
Index: subscriptions.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/subscriptions/subscriptions.install,v
retrieving revision 1.16
diff -u -r1.16 subscriptions.install
--- subscriptions.install	18 Apr 2009 20:26:35 -0000	1.16
+++ subscriptions.install	22 Aug 2009 02:32:20 -0000
@@ -48,7 +48,8 @@
       'last_sent'     => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0)),
     'primary key'     => array('sqid'),
     'indexes'         => array(
-      'load_args'     => array('load_args', 'load_function', 'uid')),
+      'load_args'     => array('load_args', 'load_function', 'uid'),
+      'uid'           => array('uid')),
   );
 
 
@@ -65,12 +66,19 @@
       'autosub_on_post'       => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => -1),
       'autosub_on_update'     => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => -1),
       'autosub_on_comment'    => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => -1),
-      'send_self'             => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => -1),
-      'last_sent'             => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0)),
+      'send_self'             => array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => -1)),
     'primary key'             => array('uid'),
   );
 
 
+  $schema['subscriptions_last_sent'] = array(
+    'fields'          => array(
+      'uid'           => array('type' => 'int', 'not null' => FALSE),
+      'send_interval' => array('type' => 'int', 'not null' => FALSE),
+      'last_sent'     => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0)),
+    'primary key'     => array('uid', 'send_interval'),
+  );
+
   return $schema;
 }
 
@@ -387,3 +395,28 @@
   variable_del('subscriptions_email_subject');
   return $ret;
 }
+
+/**
+ * Database update function 6101: Add the {subscriptions_last_sent} table.
+ */
+function subscriptions_update_6101() {
+  $ret = array();
+
+  $schema['subscriptions_last_sent'] = array(
+    'fields'          => array(
+      'uid'           => array('type' => 'int', 'not null' => TRUE),
+      'send_interval' => array('type' => 'int', 'not null' => TRUE),
+      'last_sent'     => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0)),
+    'primary key'     => array('uid', 'send_interval'),
+  );
+  
+  db_create_table($ret, 'subscriptions_last_sent', $schema['subscriptions_last_sent']);
+  db_add_index($ret, 'subscriptions_queue', 'uid', array('uid'));
+  
+  foreach (_subscriptions_send_intervals() as $send_interval => $text) {
+    db_query("INSERT INTO {subscriptions_last_sent} (uid, send_interval, last_sent) SELECT uid, %d, last_sent FROM {subscriptions_user} WHERE uid > 0", $send_interval);
+  }
+//  db_drop_field($ret, 'subscriptions_user', 'last_sent');  // not dropping this column allows going back to RC1
+  return $ret;
+}
+
Index: subscriptions_mail.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/subscriptions/subscriptions_mail.module,v
retrieving revision 1.24
diff -u -r1.24 subscriptions_mail.module
--- subscriptions_mail.module	19 Aug 2009 16:15:57 -0000	1.24
+++ subscriptions_mail.module	22 Aug 2009 02:32:21 -0000
@@ -27,7 +27,6 @@
   $loaded_objects = array();
   $users = array();
   $fields = array();
-  $mails = array();
 
   // Strategy for cron:
   // Use 50% of the remaining time to process queue items, send single messages, and assemble digest messages;
@@ -37,11 +36,11 @@
   $available_seconds = $total_seconds - $lost_seconds;
   //TEST: watchdog('cron', "Subscriptions has $available_seconds of $total_seconds seconds available.");
 
-  while (($mails_allowed <= 0 || $single_count + count($mails) < $mails_allowed)
+  while (($mails_allowed <= 0 || $single_count + $digest_count < $mails_allowed)
           && $total_seconds - timer_read('page')/1000 > $available_seconds*variable_get('subscriptions_cron_percent', 50)/100) {
     $result = db_query_range('SELECT * FROM {subscriptions_queue} WHERE last_sent + send_interval < %d ORDER BY sqid', time(), 0, 1);
     if (!($s = db_fetch_array($result))) {
-      break;  // No more subscriptions, terminate loop.
+      break;  // No more ready queue items, terminate loop.
     }
     
     if (!isset($users[$s['uid']])) {
@@ -53,7 +52,8 @@
     $user = $users[$s['uid']];
     drupal_init_language();
     $langcode = $language->language;
-
+    $user_mails = array();
+    
     do {  // once and repeat while adding to a digest
       if ($user->status && $user->access) {
         $cids = array();
@@ -134,18 +134,19 @@
             $body .= t('| Mailkey: @mailkey/@langcode', array('@mailkey' => $mailkey, '@langcode' => $langcode)) ."\n";
           }
           if ($digest) {
-            $mails[$s['uid']]['bodies'][] = $body;
-            $mails[$s['uid']]['send'] = array(
+            $user_mails['bodies'][] = $body;
+            $user_mails['send'] = array(
               'name' => $s['name'],
               'mail' => $s['mail'],
               'from' => $from,
               '!name' => $mailvars['!name'],
               '!manage_url' => $mailvars['!manage_url'],
             );
+            $user_mails['send_intervals'][$s['send_interval']] = $s['send_interval'];
           }
           else {
             $subject = strtr(subscriptions_mail_template_preprocess($subject_template, $mailvars), $mailvars);
-            _subscriptions_mail_send('passthru', $s['name'], $s['mail'], $subject, $body, $from, $s['uid']);
+            _subscriptions_mail_send('passthru', $s['name'], $s['mail'], $subject, $body, $from, $s['uid'], array($s['send_interval']));
             ++$single_count;
           }
         }
@@ -153,41 +154,31 @@
       db_query("DELETE FROM {subscriptions_queue} WHERE load_function = '%s' AND load_args = '%s' AND uid = %d", $s['load_function'], $s['load_args'], $s['uid']);
 
       if ($digest) {
-        // TODO: Get the next queue item for this user and finish off this user's digest
-        // before moving on to the next user. All messages in one digest together count
-        // as one mail, and if the number of mails is limited (per cron run), we must
-        // not let this cause a split up of the digest.
-        // Issue: We must know which notifications to send according to their send_interval.
+        // Get next ready queue item for this user.
+        $result = db_query_range('SELECT * FROM {subscriptions_queue} WHERE uid = %d AND last_sent + send_interval < %d ORDER BY sqid', $user->uid, time(), 0, 1);
+        if (!($s = db_fetch_array($result))) {
+          // No more ready queue items for this user, finish off this digest.
+          $s = $user_mails['send'];
+          $subject_template = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY, $langcode, 'subject', 'DSUBJ');
+          $body_template = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY, $langcode, 'body', 'DBODY');
+          $separator = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY .'+item', $langcode, 'subject', 'SEP');
+          $mailvars['!bodies'] = implode($separator, $user_mails['bodies']);
+          $mailvars['!name'] = $s['!name'];
+          $mailvars['!manage_url'] = $s['!manage_url'];
+          $subject = strtr(subscriptions_mail_template_preprocess($subject_template, $mailvars), $mailvars);
+          $body = strtr(subscriptions_mail_template_preprocess($body_template, $mailvars), $mailvars);
+          _subscriptions_mail_send(SUBSCRIPTIONS_DIGEST_MAILKEY, $s['name'], $s['mail'], $subject, $body, $s['from'], $user->uid, $user_mails['send_intervals']);
+          ++$digest_count;
+          $digest = false;
+        }
       }
-    } while ( FALSE );  // TODO: while adding to a digest
+    } while ( $digest );
 
     $user = $saved_user;
     $language = $saved_language;
     session_save_session(TRUE);
   }
 
-  if ($mails) {
-    session_save_session(FALSE);
-    foreach ($mails as $uid => $user_mails) {
-      $user = $users[$uid];
-      drupal_init_language();
-      $langcode = $language->language;
-      $s = $user_mails['send'];
-      $subject_template = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY, $langcode, 'subject', 'DSUBJ');
-      $body_template = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY, $langcode, 'body', 'DBODY');
-      $separator = subscriptions_mail_template_load(SUBSCRIPTIONS_DIGEST_MAILKEY .'+item', $langcode, 'subject', 'SEP');
-      $mailvars['!bodies'] = implode($separator, $user_mails['bodies']);
-      $mailvars['!name'] = $s['!name'];
-      $mailvars['!manage_url'] = $s['!manage_url'];
-      $subject = strtr(subscriptions_mail_template_preprocess($subject_template, $mailvars), $mailvars);
-      $body = strtr(subscriptions_mail_template_preprocess($body_template, $mailvars), $mailvars);
-      _subscriptions_mail_send(SUBSCRIPTIONS_DIGEST_MAILKEY, $s['name'], $s['mail'], $subject, $body, $s['from'], $uid);
-      ++$digest_count;
-    }
-    $user = $saved_user;
-    $language = $saved_language;
-    session_save_session(TRUE);
-  }
   if ($single_count + $digest_count > 0) {
     $watchdog = 'watchdog';  // keep potx from translating 'cron'
     $watchdog('cron', '!module sent !single_count single and !digest_count digest notifications in !used_seconds of !available_seconds available seconds; !remaining_items queue items left.', array(
@@ -219,7 +210,7 @@
 /**
  * Send the notification by mail.
  */
-function _subscriptions_mail_send($mailkey, $name, $to, $subject, $body, $from, $uid) {
+function _subscriptions_mail_send($mailkey, $name, $to, $subject, $body, $from, $uid, $send_intervals) {
   global $user;
 
   $mail_success = drupal_mail('subscriptions_mail', $mailkey, $to, user_preferred_language($user), array(
@@ -237,9 +228,11 @@
     if (variable_get('subscriptions_watchgood', 1)) {
       watchdog('subscriptions', 'notification for @name at @to', $watchdog_params);
     }
-    db_query("UPDATE {subscriptions_user} SET last_sent = %d WHERE uid = %d", time(), $uid);
-    if (!db_affected_rows()) {
-      @db_query("INSERT INTO {subscriptions_user} (uid, last_sent) VALUES(%d, %d)", $uid, time());
+    foreach ($send_intervals as $send_interval) {
+      db_query("UPDATE {subscriptions_last_sent} SET last_sent = %d WHERE uid = %d AND send_interval = %d", time(), $uid, $send_interval);
+      if (!db_affected_rows()) {
+        @db_query("INSERT INTO {subscriptions_last_sent} (uid, send_interval, last_sent) VALUES(%d, %d, %d)", $uid, $send_interval, time());
+      }
     }
   }
   else {
