--- tarballs/simplenews/simplenews.module	Fri Feb 17 20:08:38 2006
+++ modules/simplenews/simplenews.module	Mon Feb 20 16:28:56 2006
@@ -107,6 +107,9 @@ function simplenews_menu($may_cache) {
     $items[] = array('path' => 'admin/newsletter/users/export', 'title' => t('export subscriptions'),
                      'access' => user_access('administer newsletters'),
                      'type' => MENU_LOCAL_TASK, 'weight' => -8);
+    $items[] = array('path' => 'admin/newsletter/users/roles', 'title' => t('role subscriptions'),
+                     'access' => user_access('administer newsletters'),
+                     'type' => MENU_LOCAL_TASK, 'weight' => -7);
                      
     $items[] = array('path' => 'admin/newsletter/settings', 'title' => t('settings'),
                      'access' => user_access('administer newsletters'),
@@ -309,6 +312,22 @@ function simplenews_validate_taxonomy($t
  */
 function simplenews_cron() {
   _sn_send(FALSE);
+  // Database cleanup for roles that don't exist anymore.
+  // This must be done as a cron because there is no hook in Drupal to
+  // use when a role is deleted.
+  $roles = user_roles(1);
+  $roles_with_subscriptions = db_query('SELECT DISTINCT (rid) FROM {sn_role_subscription} s WHERE 1');
+  while ($role = db_fetch_object($roles_subscriptions)) {
+    if (!in_array($role, $roles)) {
+      $deleted_newsletter_subscriptions = db_query('SELECT s.snid FROM {sn_snid_tid} s WHERE role_subscription = %d', $role);
+      db_query('DELETE FROM {sn_role_subscriptions} WHERE rid = %d', $role);
+      db_query('DELETE FROM {sn_snid_tid} WHERE role_subscription = %d', $role);
+    }
+    // Delete users not subscribed to any newsletter
+    while($subscription = db_fetch_object($deleted_newsletter_subscriptions)) {
+      _sn_db_cleanup($subscription->snid);
+    }
+  }
 }
 
 /**
@@ -419,6 +438,20 @@ function simplenews_user($op, &$edit, &$
         if ($result = db_fetch_object(db_query($query, $edit['mail']))) {
           db_query("UPDATE {sn_subscriptions} SET uid = %d WHERE snid = %d", $edit['uid'], $result->snid);
         }
+
+        // Find all newsletters that have authenticated users as subscribers
+        $result = db_query('SELECT tid FROM {sn_role_subscriptions} WHERE rid = 2');
+        if ($result) {
+          db_query("INSERT INTO {sn_subscriptions} (mail, uid, a_status) VALUES ('%s', %d, %d)", $edit['email'], $edit['uid'], 1);
+          $watchdog = t('User %email added to the database.', array('%email'=>theme('placeholder', $edit['email'])));
+          watchdog('newsletter', $watchdog);
+        }
+
+        // Add user to all newsletters that have authenticated users as subscribers
+        $snid = db_result(db_query('SELECT snid FROM {sn_subscriptions} WHERE mail = "%s"', $edit['email']));
+        while ($newsletter = db_fetch_object($result)) {
+          db_query("INSERT INTO {sn_snid_tid} (snid, tid, role_subscription) VALUE (%d, %d, %d)", $snid, $newsletter->tid, 2);
+        }
       }
     break;
     case 'update':
@@ -434,6 +467,29 @@ function simplenews_user($op, &$edit, &$
             db_query("UPDATE {sn_subscriptions} SET uid = %d WHERE snid = %d", $account->uid, $result->snid);
           }
         }
+
+        // Update subscription roles
+        $roles = $edit['roles'];
+        if ($roles) { // No action needed if user doesn't belong to a role
+          // Get user's subscription id
+          $snid = db_result(db_query('SELECT FROM {sn_subscriptions} WHERE s.uid = %d', $account->uid));
+          // Delete all user's old role subscriptions
+          db_query('DELETE FROM {sn_snid_tid} WHERE snid = %d AND role_subscription != 0', $snid);
+
+          // Add user's role subscriptions per user's new roles
+          foreach ($roles as $role) {
+            // Determine which newsletters are subscribed to a role
+            $role_subscriptions = db_query('SELECT tid FROM {sn_role_subscriptions} s WHERE rid = %d', $role);
+            while ($role_subscription = db_fetch_object($role_subscriptions)) {
+              // Check to see if user has subscribed as an individual subscription
+              $individual_subscription = db_result(db_querey('SELECT snid FROM {sn_snid_tid} s WHERE tid = %d AND role_subscription = 0', $role_subscription->tid));
+              if (!individual_subscription) {
+                db_query('INSERT INTO {sn_snid_tid} (snid, tid, role_subscription) VALUES (%d, %d, %d)', $snid, $role_subscription->tid, $role);
+              }
+  }
+          }
+          _sn_db_cleanup($subs->snid);
+        }
       }
       elseif ($category == 'newsletter' && user_access('subscribe to newsletters')) {
         _simplenews_subscription_manager(FALSE, FALSE, TRUE);
@@ -443,6 +499,8 @@ function simplenews_user($op, &$edit, &$
       $query = "SELECT snid FROM {sn_subscriptions} WHERE uid = %d";
       if ($result = db_fetch_object(db_query($query, $account->uid))) {
         db_query("UPDATE {sn_subscriptions} SET uid = %d WHERE snid = %d", 0, $result->snid);
+        // Delete all user's role subscriptions
+        db_query('DELETE FROM {sn_snid_tid} WHERE snid = %d AND role>subscription = 1', $result->snid);
       }
     break;
     case 'form':
@@ -630,16 +688,13 @@ function simplenews_process_subscription
       }
       else {
         if (db_num_rows($snid_result)) {
-          $query = "DELETE FROM {sn_snid_tid} WHERE snid = %d AND tid = %d";
+          // Set 'user_unsubscribed_self' value to 1
+          db_query('UPDATE {sn_snid_tid} SET user_unsubscribed_self = %d WHERE snid = %d AND tid = %d AND role_subscription != 0', 1, $snid_obj->snid, $tid);
+          $query = "DELETE FROM {sn_snid_tid} WHERE snid = %d AND tid = %d AND user_unsubscribed_self = 0";
           if (db_affected_rows(db_query($query, $snid_obj->snid, $tid))) {
             simplenews_handle_messages(t('Your newsletter subscriptions have been updated.'), t('Your newsletter subscriptions have been updated.'));
           }
-          //Perform db cleanup tasks
-          if (!db_num_rows(db_query('SELECT tid FROM {sn_snid_tid} WHERE snid = %d', $snid_obj->snid))) {
-            db_query('DELETE FROM {sn_subscriptions} WHERE snid = %d', $snid_obj->snid);
-            $watchdog = t('User %email deleted from the database.', array('%email'=>theme('placeholder', $mail)));
-            watchdog('newsletter', $watchdog);
-          }
+          _sn_db_cleanup($snid_obj->snid);
         }
       }
     }
@@ -906,6 +961,121 @@ function simplenews_node_prepare($nid, $
   return $node;
 }
 
+// Database cleanup: delete subscribers no longer subscribed to any newsletter
+function _sn_db_cleanup($snid) {
+  if (!db_num_rows(db_query('SELECT tid FROM {sn_snid_tid} WHERE snid = %d AND user_unsubscribed_self = 1', $snid))) {
+    db_query('DELETE FROM {sn_subscriptions} WHERE snid = %d', $snid);
+  }
+  $watchdog = t('User %email deleted from the database.', array('%email'=>theme('placeholder', $subs->mail)));
+  watchdog('newsletter', $watchdog);
+}
+
+function _sn_unsubscribe_delete($result, $tid, $role = 0) {
+  while ($user = db_fetch_object($result)) {
+    db_query("DELETE FROM {sn_snid_tid} WHERE snid = %d AND tid = %d AND role_subscription = %d", $user->snid, $tid, $role);
+    _sn_db_cleanup($user->snid);
+  }
+  drupal_set_message(t('Deleted role from subscriptions.'));
+}
+
+function _sn_unsubscribe_roles($roles_unsubscribed, $tid) {
+  if (in_array(2, $roles_unsubscribed)) {
+    foreach($roles_unsubscribed as $role) {
+      $result = db_query('SELECT DISTINCT(s.snid), s.uid FROM {users} u INNER JOIN {sn_subscriptions} s ON u.uid = s.uid');
+      _sn_unsubscribe_delete($result, $tid, $role);
+    }
+    return;
+  }
+  else {
+    foreach ($roles_unsubscribed as $role) {
+      $result = db_query('SELECT DISTINCT(s.snid) FROM {users_roles} u INNER JOIN {sn_subscriptions} s ON u.uid = s.uid WHERE u.rid = %d', $role);
+      _sn_unsubscribe_delete($result, $tid, $role);
+    }
+  }
+}
+
+function _sn_subscribe_users($emails, $type, $tid, $tree, $role = 0) {
+  if (!$emails) {
+    return;
+  }
+  $emails = ltrim($emails, ',');
+  $emails = explode(",", $emails);
+  foreach ($emails as $email) {
+    $email = trim($email);
+    if (valid_email_address($email)) {
+      $result = db_query("SELECT snid FROM {sn_subscriptions} WHERE mail = '%s'", $email);
+      if (!db_num_rows($result)) {
+        $query = "SELECT uid FROM {users} WHERE mail = '%s'";
+        if ($result = db_fetch_object(db_query($query, $email))) {
+          $uid = $result->uid;
+        }
+        else {
+          $uid = 0;
+        }
+        if (db_query("INSERT INTO {sn_subscriptions} (mail, uid, a_status) VALUES ('%s', %d, %d)", $email, $uid, 1)) {
+          $result = db_query("SELECT snid FROM {sn_subscriptions} WHERE mail = '%s'", $email);
+          $watchdog = t('User %email added to the database.', array('%email'=>theme('placeholder', $email)));
+          watchdog('newsletter', $watchdog);
+        }
+      }
+      if (db_num_rows($result)) $added[] .= $email;
+      if ($tree) {
+        $snid = db_result($result);
+        if ($type == 'import_subscriptions') {
+          foreach ($tree as $newsletter) {
+            if ($tid['tid_'.$newsletter->tid]) {
+              $newsletter_names[] = $newsletter->name;
+              $snid_tid = db_query('SELECT snid FROM {sn_snid_tid} WHERE snid = %d AND tid = %d AND role_subscription = 0', $snid, $newsletter->tid, $role);
+              if (!db_num_rows($snid_tid)) {
+                db_query('INSERT INTO {sn_snid_tid} (snid, tid, role_subscription, user_unsubscribed_self) VALUES (%d, %d, %d, %d)', $snid, $newsletter->tid, 0, 0);
+                // DELETE roles subscriptions for user here because
+                // an individual subscription has priority over a role subscription
+                db_query('DELETE FROM {sn_snid_tid} WHERE snid = %d AND role_subscription != 0', $snid);
+              }
+
+            }
+          }
+        }
+        else {
+          $newsletter = taxonomy_get_term($tid);
+          $newsletter_name = $newsletter->name;
+          $snid_tid = db_query('SELECT snid FROM {sn_snid_tid} WHERE snid = %d AND tid = %d AND role_subscription = %d AND user_unsubscribed_self = 0', $snid, $tid, $role);
+          if (!db_num_rows($snid_tid)) {
+            db_query('INSERT INTO {sn_snid_tid} (snid, tid, role_subscription) VALUES (%d, %d, %d)', $snid, $tid, $role);
+          }
+        }
+      }
+    }
+    else {
+      $invalid[] .= $email;
+    }
+  }
+
+  if ($added) {
+    $added = implode(", ", $added);
+    if ($type == 'role_subscriptions') {
+      drupal_set_message(t("The following addresses were added or updated to <strong>$newsletter_name</strong>: %added.", array('%added'=>theme('placeholder', $added))));
+    }
+    elseif ($type == 'import_subscriptions') {
+      drupal_set_message(t("The following addresses were added or updated to <strong>" . implode (', ', $newsletter_names) . "</strong>: %added.", array('%added'=>theme('placeholder', $added))));
+    }
+  }
+  else {
+    if ($type == 'role_subscriptions') {
+      drupal_set_message(t("No addresses were added to <strong>$newsletter_name.</strong>"));
+    }
+    elseif ($type == 'import_subscriptions') {
+      drupal_set_message(t("No addresses were added to <strong>" . explode ($newsletter_names, ', ') . "</strong>"));
+    }
+  }
+  if ($invalid) {
+    $invalid = implode(", ", $invalid);
+    drupal_set_message(t('The following addresses were invalid: %invalid.', array('%invalid'=>theme('placeholder', $invalid))), 'error');
+  }
+}
+
+
+
 /**
 * Send the newsletter
 */
@@ -928,7 +1099,7 @@ function _sn_send($timer = FALSE) {
     $term = taxonomy_get_term($nid->tid);
     $node = simplenews_node_prepare($nid->nid, $nid->tid);
     $node->title = "[$term->name] ".$node->title;
-    $result2 = db_query('SELECT s.mail, s.snid FROM {sn_subscriptions} s INNER JOIN {sn_snid_tid} t ON s.snid = t.snid WHERE s.s_status = %d AND s.a_status = %d AND t.tid = %d ORDER BY s.snid ASC', 0, 1, $nid->tid);
+    $result2 = db_query('SELECT DISTINCT (s.mail), s.snid FROM {sn_subscriptions} s INNER JOIN {sn_snid_tid} t ON s.snid = t.snid WHERE s.s_status = %d AND s.a_status = %d AND t.tid = %d AND user_unsubscribed_self = 0 ORDER BY s.snid ASC', 0, 1, $nid->tid);
     while ($mail = db_fetch_object($result2)) {
       $md5 = md5($mail->mail . simplenews_private_key());
       $h = drupal_substr($md5, 0, 10).$mail->snid.'t'.$nid->tid;
@@ -1304,11 +1476,14 @@ function simplenews_admin($op = NULL, $o
         $output .= _simplenews_subscription_manager(FALSE, $snid);
       }
       elseif ($op2 == 'add') {
-        $output .= simplenews_admin_list_add();
+        $output .= simplenews_admin_list_add('import_subscriptions');
       }
       elseif ($op2 == 'export') {
         $output .= simplenews_admin_list_export();
       }
+      elseif ($op2 == 'roles') {
+        $output .= simplenews_admin_list_add('role_subscriptions');
+      }
       else {
         $output .= simplenews_admin_list();
       }
@@ -1372,7 +1547,7 @@ function simplenews_admin_news($sent) {
       '#default_value' => $_SESSION['simplenews_drafts_filter'],
     );
     $query = "SELECT n.*, s.s_status FROM {node} n INNER JOIN {sn_newsletters} s ON n.nid = s.nid WHERE s.s_status = %d".$queries[$_SESSION['simplenews_drafts_filter']]." ORDER BY n.created DESC";
-    $count_query = "SELECT COUNT(n.nid) FROM {node} n INNER JOIN {sn_newsletters} s ON n.nid = s.nid WHERE s.s_status = %d".$queries[$_SESSION['simplenews_drafts_filter']];
+    $count_query = "SELECT COUNT(n.nid) FROM {node} n INNER JOIN {sn_newsletters} s ON n.nid = s.nid WHERs_status = %d".$queries[$_SESSION['simplenews_drafts_filter']];
   }
   else {
     list($names, $queries) = array_values(simplenews_set_filter('simplenews_sent_filter'));
@@ -1490,62 +1665,65 @@ function simplenews_admin_list() {
   return $output;
 }
 
-function simplenews_admin_list_add() {
+function simplenews_admin_list_add($type = 'import_subscriptions') {
   $edit = $_POST['edit'];
   $tree = taxonomy_get_tree(simplenews_get_vid());
 
   if ($_POST['op'] == t('Import')) {
-    if ($edit['emails'] != '') {
-      $emails = explode(",", $edit['emails']);
-       foreach ($emails as $email) {
-        $email = trim($email);
-        if (valid_email_address($email)) {
-          $result = db_query("SELECT snid FROM {sn_subscriptions} WHERE mail = '%s'", $email);
-          if (!db_num_rows($result)) {
-            $query = "SELECT uid FROM {users} WHERE mail = '%s'";
-            if ($result = db_fetch_object(db_query($query, $email))) {
-              $uid = $result->uid;
-            }
-            else {
-              $uid = 0;
-            }
-            if (db_query("INSERT INTO {sn_subscriptions} (mail, uid, a_status) VALUES ('%s', %d, %d)", $email, $uid, 1)) {
-              $result = db_query("SELECT snid FROM {sn_subscriptions} WHERE mail = '%s'", $email);
-              $watchdog = t('User %email added to the database.', array('%email'=>theme('placeholder', $email)));
-              watchdog('newsletter', $watchdog);
-            }
-          }
-          if (db_num_rows($result)) $added[] .= $email;
+    if ($type == 'role_subscriptions') {
           if ($tree) {
-            $snid = db_result($result);
             foreach ($tree as $newsletter) {
-              if ($edit['tid_'.$newsletter->tid]) {
-                $snid_tid = db_query('SELECT snid FROM {sn_snid_tid} WHERE snid = %d AND tid = %d', $snid, $newsletter->tid);
-                if (!db_num_rows($snid_tid)) {
-                  db_query('INSERT INTO {sn_snid_tid} (snid, tid) VALUES (%d, %d)', $snid, $newsletter->tid);
-                }
+          $checked_roles = $edit['checked_roles_'.$newsletter->tid];
+          $checked_roles = ($checked_roles ? $checked_roles : array());
+          $roles_subscribed_to_newsletter = db_query('SELECT rid FROM {sn_role_subscriptions} u WHERE tid = %d', $newsletter->tid);
+
+          // Delete roles from subscriptions
+          $roles_unsubscribed = array();
+          $roles_subscribed = array();
+          while ($row = db_fetch_object($roles_subscribed_to_newsletter)) {
+            if (!in_array($row->rid, $checked_roles)) {
+              db_query('DELETE FROM {sn_role_subscriptions} WHERE tid = %d AND rid = %d', $newsletter->tid, $row->rid);
+              $roles_unsubscribed[] = $row->rid;
               }
+            $roles_subscribed[] = $row->rid;
             }
+
+          // Add roles to subscriptions
+          $roles_to_add = array();
+          $roles_to_add = array_diff($checked_roles, $roles_subscribed);
+          $roles_where = array();
+          foreach ($roles_to_add as $role) {
+            db_query('INSERT INTO {sn_role_subscriptions} (tid, rid) VALUES (%d, %d)', $newsletter->tid, $role);
           }
+          $result_users = '';
+          if (in_array(2, $checked_roles)) {
+            $result_users = db_query('SELECT u.uid FROM {users} u WHERE u.status != 0');
         }
         else {
-          $invalid[] .= $email;
+            foreach ($checked_roles as $rid) {
+              $result_users = db_query('SELECT DISTINCT(s.uid) FROM {users_roles} s INNER JOIN {users} u ON u.uid = s.uid WHERE u.status != 0 AND s.rid = %d', $rid);
+              while ($uid = db_fetch_object($result_users)) {
+                $account = user_load(array('uid' => $uid->uid, 'status' => 1));
+                if ($account->mail) {
+                  $emails .= ",$account->mail";
         }
       }
+              _sn_subscribe_users($emails, $type, $newsletter->tid, $tree, $rid);
+              unset ($emails);
+            }
+          }
+          if ($roles_unsubscribed) {
+            _sn_unsubscribe_roles($roles_unsubscribed, $newsletter->tid);
     }
-    if ($added) {
-      $added = implode(", ", $added);
-      drupal_set_message(t('The following addresses were added or updated: %added.', array('%added'=>theme('placeholder', $added))));
     }
-    else {
-      drupal_set_message(t('No addresses were added.'));
     }
-    if ($invalid) {
-      $invalid = implode(", ", $invalid);
-      drupal_set_message(t('The following addresses were invalid: %invalid.', array('%invalid'=>theme('placeholder', $invalid))), 'error');
+    }
+    if ($type = 'import_subscriptions') {
+      _sn_subscribe_users($edit['emails'], $type, $edit, $tree);
     }
   }
   
+  if ($type == 'import_subscriptions') {
   $form['emails'] = array(
     '#type' => 'textarea',
     '#title' => t('E-mail addresses'),
@@ -1571,9 +1749,34 @@ function simplenews_admin_list_add() {
     }
     if ($to && $added) {
       $to = implode(", ", $to);
-      drupal_set_message(t('The addresses were subscribed to the following newsletters: %to.', array('%to'=>theme('placeholder', $to))));
+drupal_set_message(t('The addresses were subscribed to the following newsletters: %to.', array('%to'=>theme('placeholder', $to))));
+      }
+    }
+  }
+  if ($type == 'role_subscriptions') {
+    foreach ($tree as $newsletter) {
+  $form['roles']['tid_'.$newsletter->tid] = array(
+        '#type' => 'fieldset',
+        '#title' => $newsletter->name,
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+  );
+      $subscribed_roles = array();
+      $roles = db_query('SELECT rid FROM {sn_role_subscriptions} s WHERE s.tid = %d', $newsletter->tid);
+      while ($role = db_fetch_object($roles)) {
+        $subscribed_roles[] = $role->rid;
+      }
+       $form['roles']['tid_'.$newsletter->tid]['checked_roles_'.$newsletter->tid] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Role subscriptions'),
+        '#default_value' => $subscribed_roles,
+        '#options' => user_roles(1),
+        '#description' => t('Send this newsletter to users in selected roles.'),
+        '#weight' => 0,
+      );
     }
   }
+
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Import'),
@@ -2045,11 +2248,7 @@ function simplenews_confirm_subscription
           db_query("DELETE FROM {sn_snid_tid} WHERE snid = %d AND tid = %d", $subs->snid, $tid);
           drupal_set_message(t('%user was successfully removed from the %newsletter subscription list.', array('%user'=>theme('placeholder', $subs->mail), '%newsletter'=>theme('placeholder',$newsletter->name))));
           //Perform db cleanup tasks
-          if (!db_num_rows(db_query('SELECT tid FROM {sn_snid_tid} WHERE snid = %d', $subs->snid))) {
-            db_query('DELETE FROM {sn_subscriptions} WHERE snid = %d', $subs->snid);
-            $watchdog = t('User %email deleted from the database.', array('%email'=>theme('placeholder', $subs->mail)));
-            watchdog('newsletter', $watchdog);
-          }
+          _sn_db_cleanup($subs->snid);
           drupal_goto();
         }
         else {
