Index: invite.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/invite/invite.install,v
retrieving revision 1.3.2.25
diff -u -r1.3.2.25 invite.install
--- invite.install	12 Nov 2007 21:47:22 -0000	1.3.2.25
+++ invite.install	12 Nov 2007 21:54:01 -0000
@@ -17,6 +17,7 @@
           expiry int(11) NOT NULL default '0',
           timestamp int(11) NOT NULL default '0',
           received tinyint(3) unsigned NOT NULL default '0',
+          resent tinyint(3) unsigned NOT NULL default '0',
           data text NOT NULL,
           PRIMARY KEY  (email),
           UNIQUE (reg_code),
@@ -35,6 +36,7 @@
           expiry INTEGER NOT NULL DEFAULT 0,
           timestamp INTEGER NOT NULL DEFAULT 0,
           received SMALLINT NOT NULL DEFAULT 0,
+          resent SMALLINT NOT NULL DEFAULT 0,
           data TEXT NOT NULL DEFAULT '',
           PRIMARY KEY (email),
           UNIQUE (reg_code)
@@ -333,3 +335,20 @@
   return $ret;
 }
 
+/**
+ * Add resent count.
+ */
+function invite_update_12() {
+  $ret = array();
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      $ret[] = update_sql("ALTER TABLE {invite} ADD COLUMN resent tinyint(3) unsigned NOT NULL default '0'");
+      break;
+    case 'pgsql':
+      db_add_column($ret, 'invite', 'resent', 'SMALLINT', array('not null' => TRUE, 'default' => '0'));
+      break;
+  }
+  return $ret;
+}
+
Index: invite.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/invite/invite.module,v
retrieving revision 1.10.2.87
diff -u -r1.10.2.87 invite.module
--- invite.module	12 Nov 2007 21:03:57 -0000	1.10.2.87
+++ invite.module	12 Nov 2007 21:54:02 -0000
@@ -90,7 +90,7 @@
       'path' => 'invite',
       'title' => variable_get('invite_page_title', t('Invite your friends and colleagues')),
       'callback' => 'drupal_get_form',
-      'callback arguments' => array('invite_form', 'page'),
+      'callback arguments' => array('invite_form', 'page', array(), FALSE),
       'access' => $send_access,
       'type' => MENU_NORMAL_ITEM,
     );
@@ -142,9 +142,22 @@
       'type' => MENU_CALLBACK,
     );
   }
-  else if ($user->uid && $send_access) {
+  else {
     // Check for newly registered users
-    _invite_check_messages($user->uid);
+    if ($user->uid && $send_access) {
+      _invite_check_messages($user->uid);
+    }
+
+    if (arg(0) == 'invite' && arg(1) == 'resend') {
+      $items[] = array(
+        'path' => 'invite/resend/'. arg(2),
+        'title' => t('Resend invitation'),
+        'callback' => 'invite_resend',
+        'callback arguments' => arg(2),
+        'access' => $send_access,
+        'type' => MENU_LOCAL_TASK,
+      );
+    }
   }
 
   return $items;
@@ -606,6 +619,7 @@
       }
       $row[] = $account_exists ? t('Accepted') : t('Deleted');
       $row[] = $allow_delete ? $delete_link : '';
+      $row[] = '';
     }
     else {
       // Pending/expired
@@ -614,6 +628,7 @@
       $row[]  = check_plain($invite->email);
       $row[] = $expired ? t('Expired') : t('Pending');
       $row[] = $delete_link;
+      $row[] = $expired ? l(t('Resend'), "invite/resend/{$invite->reg_code}") : '';
     }
 
     $rows[] = $row;
@@ -632,7 +647,7 @@
  */
 function theme_invite_overview($items) {
   if (count($items) > 0) {
-    $headers = array(t('E-mail'), t('Status'), '');
+    $headers = array(t('E-mail'), t('Status'), array('data' => '', 'colspan' => 2));
     $output  = theme('table', $headers, $items, array('id' => 'invites'));
     $output .= theme('pager', NULL, 50, 0);
   }
@@ -648,12 +663,20 @@
  *
  * @param $op
  *   The type of form to generate, 'page' or 'block'.
+ * @param $edit
+ *   Previous values when resending an invite.
+ * @param $is_reminder
+ *   Whether or not resending an invite (doesn't count towards limit).
  * @return
  *   A form definition array.
  */
-function invite_form($op = 'page') {
+function invite_form($op = 'page', $edit = array(), $is_reminder = FALSE) {
   global $user;
 
+  if (!is_array($edit)) {
+    $edit = (array)$edit;
+  }
+
   $max_invites = invite_max_invites();
   $allow_multiple = user_access('send mass invitations');
 
@@ -668,8 +691,8 @@
         $form['#access'] = FALSE;
         return $form;
       }
-      else {
-        // Redirect to invites list
+      else if (!$is_reminder) {
+        // Redirect to invites list, except when resending an invite
         drupal_set_message(t('Sorry, you reached the maximum number (@max) of invitations.', array('@max' => $max_invites)), 'error');
         drupal_goto('invite/list');
       }
@@ -679,6 +702,14 @@
     $invites_left = INVITE_UNLIMITED_INVITES;
   }
 
+  $form['is_reminder'] = array(
+    '#type' => 'value',
+    '#value' => $is_reminder,
+  );
+  $form['reg_code'] = array(
+    '#type' => 'value',
+    '#value' => $is_reminder ? $edit['reg_code'] : NULL,
+  );
   $form['remaining_invites'] = array(
     '#type' => 'value',
     '#value' => $invites_left,
@@ -742,33 +773,57 @@
       );
 
       // Recipient email address
-      $failed_emails = '';
-
-      if (isset($_SESSION['invite_failed_emails'])) {
-        $failed_emails = implode("\n", (array)unserialize($_SESSION['invite_failed_emails']));
-        unset($_SESSION['invite_failed_emails']);
-      }
-      $form['email'] = array(
-        '#title' => t('To'),
-        '#default_value' => $failed_emails,
-        '#description' => format_plural((int)$allow_multiple + 1, 'Type the e-mail address of the person you would like to invite.', 'Type the e-mail addresses of the persons you would like to invite. Addresses should be separated by newlines or commas.'),
-        '#required' => TRUE,
-      );
-      if ($allow_multiple) {
-        $form['email']['#type'] = 'textarea';
-        $form['email']['#rows'] = 3;
+      if (!$is_reminder) {
+        $failed_emails = '';
+        if (isset($_SESSION['invite_failed_emails'])) {
+          $failed_emails = implode("\n", (array)unserialize($_SESSION['invite_failed_emails']));
+          unset($_SESSION['invite_failed_emails']);
+        }
+        $form['email'] = array(
+          '#title' => t('To'),
+          '#default_value' => $failed_emails,
+          '#description' => format_plural((int)$allow_multiple + 1, 'Type the e-mail address of the person you would like to invite.', 'Type the e-mail addresses of the persons you would like to invite. Addresses should be separated by newlines or commas.'),
+          '#required' => TRUE,
+        );
+        if ($allow_multiple) {
+          $form['email']['#type'] = 'textarea';
+          $form['email']['#rows'] = 3;
+        }
+        else {
+          $form['email']['#type'] = 'textfield';
+          $form['email']['#maxlength'] = 64;
+        }
+        if ($failed_emails) {
+          $form['email']['#attributes']['class'] = 'error';
+        }
       }
       else {
-        $form['email']['#type'] = 'textfield';
-        $form['email']['#maxlength'] = 64;
-      }
-      if ($failed_emails) {
-        $form['email']['#attributes']['class'] = 'error';
+        // The email is not editable when resending an invite
+        $allow_multiple = 0;
+        $form['email_markup'] = array(
+          '#type' => 'item',
+          '#title' => t('To'),
+          '#value' => check_plain($edit['email']),
+        );
+        $form['email'] = array(
+          '#type' => 'value',
+          '#value' => $edit['email'],
+        );
       }
 
       // Message subject
-      $subject = invite_get_subject();
-
+      if ($is_reminder && !empty($edit['data']['subject'])) {
+        // Use previous subject
+        $subject = $edit['data']['subject'];
+      }
+      else {
+        $subject = invite_get_subject();
+      }
+      // Add prefix
+      $prefix = t('Re:');
+      if ($is_reminder && substr($subject, 0, strlen($prefix)) != $prefix) {
+        $subject = $prefix .' '. $subject;
+      }
       if (variable_get('invite_subject_editable', FALSE)) {
         $form['subject'] = array(
           '#type' => 'textfield',
@@ -780,11 +835,15 @@
         );
       }
       else {
-        $form['subject'] = array(
+        $form['subject_markup'] = array(
           '#type' => 'item',
           '#title' => t('Subject'),
           '#value' => check_plain($subject),
         );
+        $form['subject'] = array(
+          '#type' => 'value',
+          '#value' => $subject,
+        );
       }
 
       // Message body
@@ -794,6 +853,7 @@
       );
       $form['message'] = array(
         '#type' => 'textarea',
+        '#default_value' => ($is_reminder && !empty($edit['data']['message'])) ? $edit['data']['message'] : '',
         '#description' => format_plural((int)$allow_multiple + 1, 'This message will be added to the mail sent to the person you are inviting.', 'This message will be added to the mail sent to the persons you are inviting.'),
       );
 
@@ -821,7 +881,13 @@
     $output .= drupal_render($form['remaining_invites_markup']);
     $output .= drupal_render($form['remaining_invites']);
     $output .= drupal_render($form['from']);
+    if (isset($form['email_markup'])) {
+      $output .= drupal_render($form['email_markup']);
+    }
     $output .= drupal_render($form['email']);
+    if (isset($form['subject_markup'])) {
+      $output .= drupal_render($form['subject_markup']);
+    }
     $output .= drupal_render($form['subject']);
 
     // Show complete invitation message
@@ -856,44 +922,46 @@
 
   $emails = _invite_get_emails($edit['email']);
 
-  if (count($emails) > 0) {
-    // Filter out already registered users, but pass validation
-    $failed_emails = _invite_validate_emails("SELECT mail AS email FROM {users} WHERE mail IN (%s)", $emails);
-    if (count($failed_emails)) {
-      $error = format_plural(count($failed_emails), 'The following recipient is already a member:', 'The following recipients are already members:') .'<br />';
-      foreach ($failed_emails as $key => $email) {
-        $account = user_load(array('mail' => $email));
-        $failed_emails[$key] = theme('username', $account) .' ('. check_plain($email) .')';
-      }
-      $error .= implode(', ', $failed_emails);
-      drupal_set_message($error, 'error');
-    }
-
-    // Filter out already invited users, but pass validation
-    $failed_emails = _invite_validate_emails("SELECT email FROM {invite} WHERE email IN (%s)", $emails);
-    if (count($failed_emails)) {
-      $error = format_plural(count($failed_emails), 'The following recipient has already been invited:', 'The following recipients have already been invited:') .'<br />';
-      $error .= implode(', ', array_map('check_plain', $failed_emails));
-      drupal_set_message($error, 'error');
-    }
-
-    // Check that there is at least one valid e-mail remaining after filtering
-    // out dupes
-    if (count($emails) == 0) {
-      form_set_error('email');
-      return;
-    }
-
-    // Check invite limit, fail to let the user choose which ones to send
-    if ($edit['remaining_invites'] != INVITE_UNLIMITED_INVITES && count($emails) > $edit['remaining_invites']) {
-      form_set_error('email', format_plural($edit['remaining_invites'], 'You have only 1 invite left.', 'You have only @count invites left.'));
-      return;
-    }
-
-    // Check number of e-mails
-    if (!user_access('send mass invitations') && count($emails) > 1) {
-      form_set_error('email', t('You cannot send more than one invitation.'));
-      return;
+  if (!$edit['is_reminder']) {
+    if (count($emails) > 0) {
+      // Filter out already registered users, but pass validation
+      $failed_emails = _invite_validate_emails("SELECT mail AS email FROM {users} WHERE mail IN (%s)", $emails);
+      if (count($failed_emails)) {
+        $error = format_plural(count($failed_emails), 'The following recipient is already a member:', 'The following recipients are already members:') .'<br />';
+        foreach ($failed_emails as $key => $email) {
+          $account = user_load(array('mail' => $email));
+          $failed_emails[$key] = theme('username', $account) .' ('. check_plain($email) .')';
+        }
+        $error .= implode(', ', $failed_emails);
+        drupal_set_message($error, 'error');
+      }
+  
+      // Filter out already invited users, but pass validation
+      $failed_emails = _invite_validate_emails("SELECT email FROM {invite} WHERE email IN (%s)", $emails);
+      if (count($failed_emails)) {
+        $error = format_plural(count($failed_emails), 'The following recipient has already been invited:', 'The following recipients have already been invited:') .'<br />';
+        $error .= implode(', ', array_map('check_plain', $failed_emails));
+        drupal_set_message($error, 'error');
+      }
+  
+      // Check that there is at least one valid email remaining after filtering
+      // out dupes
+      if (count($emails) == 0) {
+        form_set_error('email');
+        return;
+      }
+  
+      // Check invite limit, fail to let the user choose which ones to send
+      if ($edit['remaining_invites'] != INVITE_UNLIMITED_INVITES && count($emails) > $edit['remaining_invites']) {
+        form_set_error('email', format_plural($edit['remaining_invites'], 'You have only 1 invite left.', 'You have only @count invites left.'));
+        return;
+      }
+
+      // Check number of e-mails
+     if (!user_access('send mass invitations') && count($emails) > 1) {
+        form_set_error('email', t('You cannot send more than one invitation.'));
+        return;
+      }
     }
   }
 
@@ -920,9 +988,10 @@
 
   foreach ($edit['valid_emails'] as $email) {
     // Create the invite object
+    $code = isset($edit['reg_code']) ? $edit['reg_code'] : invite_regcode();
     $invite = _invite_substitutions(array(
       'email' => $email,
-      'code'  => invite_regcode(),
+      'code'  => $code,
       'data'  => array('subject' => $subject, 'message' => $message),
     ));
 
@@ -935,8 +1004,10 @@
       invite_save($invite);
 
       // Notify other modules
-      $args = array('inviter' => $invite->inviter, 'code' => $invite->code);
-      module_invoke_all('invite', 'invite', $args);
+      if (!$edit['is_reminder']) {
+        $args = array('inviter' => $invite->inviter, 'code' => $invite->code);
+        module_invoke_all('invite', 'invite', $args);
+      }
 
       $count_success++;
     }
@@ -1095,7 +1166,12 @@
   $expiry = time() + (variable_get('invite_expiry', 30)*60*60*24);
   $data = serialize($edit['data']);
 
-  return db_query("INSERT INTO {invite} (email, reg_code, uid, expiry, data) VALUES ('%s', '%s', %d, %d, '%s')", $edit['email'], $edit['code'], $edit['inviter']->uid, $expiry, $data);
+  $result = db_query("UPDATE {invite} SET expiry = %d, data = '%s', resent = resent + 1 WHERE email = '%s'", $expiry, $data, $edit['email']);
+  if (!db_affected_rows()) {
+    $result = db_query("INSERT INTO {invite} (email, reg_code, uid, expiry, data) VALUES ('%s', '%s', %d, %d, '%s')", $edit['email'], $edit['code'], $edit['inviter']->uid, $expiry, $data);
+  }
+
+  return $result;
 }
 
 /**
@@ -1159,6 +1235,26 @@
 }
 
 /**
+ * Menu callback; resend an expired invite.
+ *
+ * @param $code
+ *   Registration code of invitate to resend.
+ */
+function invite_resend($code) {
+  global $user;
+
+  $invite = invite_load($code);
+
+  // Inviter must match current user and invitation must have expired
+  if ($invite->uid == $user->uid && $invite->expiry < time()) {
+    return drupal_get_form('invite_form', 'page', $invite, TRUE);
+  }
+  else {
+    drupal_access_denied();
+  }
+}
+
+/**
  * Calculate the number of successful/pending/unsuccessful invitations.
  *
  * @param $uid

