rsvp.module

<?php
// $Id: rsvp.module,v 1.12.2.31 2008/07/16 00:17:40 owahab Exp $

/**
 * @module rsvp
 * @package rsvp - A drupal module developed for civicspace - a distribution of drupal.
 * @description Provides email invite and tracking functionality for event-enabled nodes. Requires event.module.
 * @author crunchywelch (welch@advomatic.com)
 * @author Omar Abdel-Wahab (owahab@gmail.com)
 *
 */

include(drupal_get_path('module', 'rsvp') .'/rsvp.theme');

/**
 * @defgroup rsvp_core core functions for rsvp.
 */

/**
 * Provides a pathetically small amount of help information for the rsvp module.
 *
 * @ingroup rsvp_core
 */
function rsvp_help($section) {
  switch ($section) {
    case 'admin/help#rsvp':
      global $user;
      $output = '<p>'. t('The RSVP module lets users invite people by email to events and track a list of people who will be attending.    The RSVP module requires the event module because it is necessary to have an event to invite people to first.') .'</p>';
      $output .= '<p>'. t('The RSVP module also lets users invite users subscribed to newsletters, which requires !simplenews installed, as well as invite other registered users.', array('!simplenews' => l(t('Simplenews module'), 'http://drupal.org/project/simplenews'))) .'</p>';
      $output .= '<p>'. t('The RSVP page shows a <em>RSVP</em> tab in event page and in <em>my account</em> page. There are confirmation screens for creating and editing RSVPs. Email addresses which are input for RSVP have input validation.  RSVP also creates an invitation url by hash value access so that users can click a URL and be taken directly to their invitation. For each RSVP there are view, edit, manage, and send tabs. Users can manage attendees through the manage attendees tab. Users can also send attendees a message through the send message tab.') .'</p>';
      $output .= t('<p>You can:</p>
<ul>
<li>Enable the RSVP module at <a href="!admin-modules">administer &gt;&gt; modules</a>.</li>
<li>Not administer the RSVP module.</li>
<li>Create an RSVP for an event by clicking the <strong>Create RSVP</strong> in the RSVP tab in your event.</li>
<li>View your invites at !rsvp.</li>
<li>View your RSVPs at !rsvp-manage.</li>
<li>View, edit, and invite more attendees for each RSVP.</li>
', array('!admin-modules' => url('admin/build/modules'), '!rsvp' => l(t('your invites tab'), 'user/'. $user->uid .'/rsvp'), '!rsvp-manage' => l(t('your RSVPs tab'), 'user/'. $user->uid .'/rsvp/manage'))) .'</ul>';
      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="%rsvp">RSVP page</a>.', array('%rsvp' => 'http://www.drupal.org/handbook/modules/rsvp/')) .'</p>';
      return $output;
    case 'admin/modules#description' :
      return t('Provides rsvp functionality for node types enabled in the event system.');
    case 'rsvp/'. arg(1) .'/message' :
      return t('You can send a message to the attendees of this rsvp here.');
    case 'rsvp/'. arg(1) .'/attendees' :
      return t('You can add attendees, remove attendees, or view the status of an attendee\'s invitation here.');
    case 'rsvp' :
    case 'rsvp/invites' :
      global $user;
      if (!$user->uid) {
        return t('You must %login or %register in order to manage your invitations to rsvp events from this site. Otherwise, please use the link provided in your email to reply. If the link does not work, contact the sender of the invitation to see if the event has been deleted.', array('%login' => l('login', 'user'), '%register' => l('create a user account', 'user/register')));
      }
  }
}

/**
 * Provides the rsvp permission information for the drupal system.
 *
 * @ingroup rsvp_core
 */
function rsvp_perm() {
  return array("administer rsvp", "rsvp on events", "rsvp on own events", "rsvp newsletters subscribers", "rsvp system users", "rsvp buddylist");
}

/**
* Implementation of hook_cron
*
* Processing assuring that new users get their invitations associated with their account.
*/
function rsvp_cron() {
  db_query('UPDATE {rsvp_invite} r, {users} u SET r.uid = u.uid WHERE r.uid = 0 AND r.email = u.mail');
}

/**
 * Implementation of hook_menu().
 */
function rsvp_menu($may_cache) {
  global $user;
  $items = array();

  if ($may_cache) {
    // user account tabs
    if ($user->uid != 0) {
      $items[] = array('path' => 'user/'. $user->uid .'/rsvp',
                       'title' => t('RSVP'),
                       'access' => user_access('access content'),
                       'callback' => 'rsvp_view_invites',
                       'type' => MENU_LOCAL_TASK,
                     );
      $items[] = array('path' => 'user/'. $user->uid .'/rsvp/invites',
                       'title' => t('Your invites'),
                       'access' => user_access('access content'),
                       'type' => MENU_DEFAULT_LOCAL_TASK,
                       'weight' => '0');
      $items[] = array('path' => 'user/'. $user->uid .'/rsvp/manage',
                       'title' => t('Your RSVPs'),
                       'access' => user_access('access content'),
                       'callback' => 'rsvp_manage',
                       'type' => MENU_LOCAL_TASK,
                       'weight' => '1');
    }

  }
  else {
    drupal_set_html_head(_rsvp_html_head());
    // email response path
    $items[] = array('path' => 'rsvp/email',
                     'title' => t('View invite'),
                     'callback' => 'rsvp_view_invite',
                     'callback arguments' => array(arg(2), arg(3)),
                     'access' => user_access('access content'),
                     'type' => MENU_CALLBACK);

    if (arg(0) == 'node' && is_numeric(arg(1))) {
      $nid = arg(1);
      $node = node_load($nid);
      $rid = arg(3);
      $access = (user_access('administer rsvp') || user_access('rsvp on events') || ($node->uid == $user->uid && user_access('rsvp on own events')));
      if (event_is_enabled($node->type)) {
        // define access rights
        // viewing tabs
        $items[] = array('path' => 'node/'. $nid .'/rsvp',
                         'title' => t('RSVP'),
                         'access' => $access,
                         'type' => MENU_LOCAL_TASK,
                         'callback' => 'rsvp_manage',
                         'callback arguments' => array($nid),
                         'weight' => 3,
                       );
        $items[] = array('path' => 'node/'. $nid .'/rsvp/create',
                         'title' => t('Create RSVP'),
                         'access' => $access,
                         'callback' => 'drupal_get_form',
                         'callback arguments' => array('rsvp_addedit_form', $nid),
                         'type' => MENU_CALLBACK);
        // management tabs
        if (is_numeric($rid)) {
          // rsvp paths
          $items[] = array('path' => 'node/'. $nid .'/rsvp/'. $rid .'/view',
                           'title' => t('View'),
                           'access' => $access,
                           'callback' => 'rsvp_view',
                           'callback arguments' => array($rid),
                           'type' => MENU_LOCAL_TASK,
                           'weight' => '0');
          $items[] = array('path' => 'node/'. $nid .'/rsvp/'. $rid .'/edit',
                           'title' => t('Edit'),
                           'access' => $access,
                           'callback' => 'drupal_get_form',
                           'callback arguments' => array('rsvp_addedit_form', $nid, $rid),
                           'type' => MENU_LOCAL_TASK,
                           'weight' => '1');
          $items[] = array('path' => 'node/'. $nid .'/rsvp/'. $rid .'/attendees',
                           'title' => t('Manage attendees'),
                           'access' => $access,
                           'callback' => 'rsvp_attendees',
                           'callback arguments' => array($rid),
                           'type' => MENU_LOCAL_TASK,
                           'weight' => '2');
          $items[] = array('path' => 'node/'. $nid .'/rsvp/'. $rid .'/attendees/send',
                           'title' => t('Send invites'),
                           'access' => $access,
                           'callback' => 'rsvp_attendees_send_invites',
                           'callback arguments' => array($rid, 'node/'. $nid .'/rsvp/'. $rid .'/attendees'),
                           'type' => MENU_CALLBACK,
                           'weight' => '2');
          $items[] = array('path' => 'node/'. $nid .'/rsvp/'. $rid .'/attendees/csv',
                           'title' => t('manage attendees'),
                           'access' => $access,
                           'callback' => 'rsvp_attendees_csv',
                           'callback arguments' => array($rid),
                           'type' => MENU_CALLBACK,
                           'weight' => '2');
          $items[] = array('path' => 'node/'. $nid .'/rsvp/'. $rid .'/attendees/simplenews',
                           'access' => ($access && user_access('rsvp newsletters subscribers')),
                           'callback' => 'rsvp_attendees_simplenews',
                           'callback arguments' => array(arg(6)),
                           'type' => MENU_CALLBACK,
                           'weight' => '2');
          $items[] = array('path' => 'node/'. $nid .'/rsvp/'. $rid .'/attendees/role',
                           'access' => ($access && user_access('rsvp system users')),
                           'callback' => 'rsvp_attendees_users',
                           'callback arguments' => array(arg(6)),
                           'type' => MENU_CALLBACK,
                           'weight' => '2');
          $items[] = array('path' => 'node/'. $nid .'/rsvp/'. $rid .'/message',
                           'title' => t('Send message'),
                           'access' => $access,
                           'callback' => 'drupal_get_form',
                           'callback arguments' => array('rsvp_message_form', $rid),
                           'type' => MENU_LOCAL_TASK,
                           'weight' => '3');
          $items[] = array('path' => 'node/'. $nid .'/rsvp/'. $rid .'/delete',
                           'title' => t('Delete RSVP'),
                           'access' => $access,
                           'callback' => 'drupal_get_form',
                           'callback arguments' => array('rsvp_delete_form', $rid),
                           'type' => MENU_CALLBACK);
        }
      }
    }

  }
  return $items;
}

/**
* Act on nodes defined by other modules.
*
* @ingroup rsvp_functions
* @param $node The requested node.
* @param $op The requested operation.
* @return dbresultset of the requested rsvp.
*/
function rsvp_nodeapi(&$node, $op) {
  // delete all RSVPs associated with an event when the event is deleted
  if ($op == 'delete' && event_is_enabled($node->type)) {
    $list = _rsvp_get_node_invites($node->nid);
    while ($rsvp = db_fetch_object($list)) {
      rsvp_delete($rsvp->rid);
    }
  }
}

/**
* Retrieves an rsvp from the database.
*
* @ingroup rsvp_functions
* @param $rid The rid of the rsvp instance.
* @return dbresultset of the requested rsvp.
*/
function rsvp_load($rid) {
  return db_fetch_object(db_query('SELECT * FROM {rsvp} WHERE rid = %d', $rid));
}

/**
* Handles the rsvp manage requests.
*
* @ingroup rsvp_core
* @return themed rsvp manage response.
*/
function rsvp_manage($nid = NULL) {

  $header = array(
    array('data' => t('Title'), 'field' => 'name', 'sort' => 'asc', 'width' => '30%'), 
    t('Invites'),
    t('Attending'),
    t('Not attending'),
    t('Might attend'),
    t('No response'),
    array('data' => t('Operations'), 'colspan' => 3),
  );

  if ($nid) {
    global $user;
    $node = node_load($nid);
    drupal_set_title($node->title);
    if (user_access('administer rsvp') || user_access('rsvp on events') || (user_access('rsvp on own events') && $node->uid == $user->uid)) {
      if ($node->event_end >= time()) {
        $content = l(t('Create RSVP'), 'node/'. $nid .'/rsvp/create');
      }
      else {
        $content = t('This event has expired, invitations can only be sent to events <br />that have not expired yet.');
      }
    }
  }
  else {
    $header = array_merge(array(array('data' => t('Event'), 'field' => 'title')), $header);
  }

  $rows = array();
  $rsvps = _rsvp_get_rsvps($nid, NULL, tablesort_sql($header));

  if (db_num_rows($rsvps)) {
    while ($rsvp = db_fetch_object($rsvps)) {
      $row = array();
      is_null($nid) ? $row[] = l($rsvp->title, 'node/'. $rsvp->nid, array('title' => 'View event')) : '';
      $row[] = l($rsvp->name, 'node/'. $rsvp->nid .'/rsvp/'. $rsvp->rid .'/view', array('title' => 'View RSVP'));
      // add statistics
      $row[] = db_num_rows(_rsvp_get_attendees($rsvp->rid));
      $row[] = db_num_rows(_rsvp_get_attendees($rsvp->rid, 'yes'));
      $row[] = db_num_rows(_rsvp_get_attendees($rsvp->rid, 'no'));
      $row[] = db_num_rows(_rsvp_get_attendees($rsvp->rid, 'maybe'));
      $row[] = db_num_rows(_rsvp_get_attendees($rsvp->rid, 'none'));
      $row[] = l(t('Edit'), 'node/'. $rsvp->nid .'/rsvp/'. $rsvp->rid .'/edit', array('title' => 'Edit RSVP'));
      $row[] = l(t('Invite'), 'node/'. $rsvp->nid .'/rsvp/'. $rsvp->rid .'/attendees', array('title' => 'Invite more people to attend your rsvp'));
      $row[] = l(t('Send a message'), 'node/'. $rsvp->nid .'/rsvp/'. $rsvp->rid .'/message', array('title' => 'Send people you invited a message'));
      $rows[] = $row;
    }
    $content .= theme('table', $header, $rows);
  }

  if (!$content) {
    // no RSVPs found for the requested user
    $content = t('You don\'t have any RSVPs.');
  }
  return $content;
}

/**
* Sets attendees for an event
*
* @ingroup rsvp_functions
* @param $attendees either an array or a string with line delimited email addresses.
* @param $rid The id of the rsvp instance.
* @return boolean true if successful
*/
function rsvp_set_invites($attendees, $rid) {
  $emails = array();
  // convert to array
  $attendees = explode("\r\n", $attendees);
  // remove duplicates
  $attendees = array_unique($attendees);

  foreach ($attendees as $key => $value) {
    // strip whitespace
    $string = trim($value);
    // attempt to deal with the string as a drupal username
    // we do this before dealing it as an e-mail to handle users like 
    // foo@somesite.com
    $user = user_load(array('name' => $string));
    if ($user === FALSE) {
      // attempt to find a system user having this string as an e-mail address
      $user = user_load(array('mail' => $string));
      if ($user === FALSE) {
        // no user found: carry on dealing with the string as an e-mail address
        if (strlen($string) && valid_email_address($string)) {
          if (!_rsvp_attendee_exists($rid, $string)) {
            // if this e-mail is not in the attendee list,
            // add it
            db_query('INSERT INTO {rsvp_invite} (rid, email, hash, timestamp) VALUES (%d, \'%s\', \'%s\', %d)', $rid, $string, md5($rid . $string . time()), time());
          }
          else {
            // the e-mail is already in the attendee list
            $emails['existing'][] = $string;
          }
        }
        else {
          // the e-mail is invalid
          $emails['invalid'][] = $string;
        }
      }
    }

    if ($user !== FALSE) {
      // a valid drupal user was found, make sure his/her e-mail isn't already
      // in the attendees list
      if (!_rsvp_attendee_exists($rid, $user->mail)) {
        db_query('INSERT INTO {rsvp_invite} (rid, uid, email, hash, timestamp) VALUES (%d, %d, \'%s\', \'%s\', %d)', $rid, $user->uid, $user->mail, md5($rid . $string . time()), time());
      }
      else {
        // the e-mail is already in the attendee list
        $emails['existing'][] = $user->name;
      }
    }
  }

  return $emails;
}

/**
* Handles the rsvp invites requests.
*
* @ingroup rsvp_core
* @return themed rsvp invites list view response.
*/
function rsvp_view_invites() {
  global $user;

  $content = '';
  $invites = _rsvp_get_invites();

  $list = array();
  while ($invite = db_fetch_object($invites)) {
    $list[$invite->nid][] = l($invite->name, "rsvp/email/". $invite->hash, array('title' => t('View invite')));
  }

  foreach ($list as $nid => $links) {
    $node = node_load($nid);
    if ($node->nid) {
      $content .= theme('item_list', $links, t('For: ') . l($node->title, 'node/'. $node->nid, array('title' => t('View this event'))) .' - '. format_date($node->event_start, 'small', '', $node->start_offset));
    }
    else {
      // node has been deleted
      $content .= theme('item_list', $links, t('Deleted event(s):'));
    }
  }
  if (count($list) == 0) {
    $content .= '<p>'. t('You have not been invited to any events yet.') .'</p>';
  }

  return $content;
}

/**
* Handles the rsvp single invite requests.
*
* @ingroup rsvp_core
* @return themed rsvp invite view response.
*/
function rsvp_view_invite($hash, $action = NULL) {
  global $user;

  $invite = _rsvp_get_invite($hash);

  switch ($action) {
  default:
    // check if the invitation exists
    if (!$invite->rid) {
      drupal_set_message(t('The invitation you requested does not exist.'));
      drupal_goto('rsvp');
    }
    $rsvp = rsvp_load($invite->rid);
    $node = node_load($rsvp->nid);
    // check if the event has been deleted
    if (!$node->nid) {
      drupal_set_message(t('The invitation you are trying to view belongs to an event that has been deleted.'));
      //drupal_goto();
    }

    // This isn't here by mistake: I think we need to log the user action
    // even if the event has expired.
    db_query('UPDATE {rsvp_invite} SET invited = 1, received = 1 WHERE hash = \'%s\'', $hash);
    // show the invitation
    $content .= rsvp_view($rsvp->rid);
    // check if the event has expired
    if (time() >= $node->event_end) {
      drupal_set_message(t('You can no longer respond to this invitation since the event has expired.'));
    }
    else {
      $content .= theme('rsvp_reply', drupal_get_form('rsvp_reply_form', $hash));

      $form = NULL;
      if (_rsvp_is_invite_viral($invite->rid)) {
        $form = drupal_get_form('rsvp_attendee_form', $invite->rid);
      }
      if (_rsvp_is_invite_message_enabled($invite->rid)) {
        $form .= '<h2>'. t('You may also message the attendees of this invite using the form below') .':</h2>';
        $form .= drupal_get_form('rsvp_message_form', $invite->rid, $hash);
      }
      if ($form) {
        $content .= theme('rsvp_invite_action', $form);
      }
    }
    $content = theme('rsvp_invite', $invite, $rsvp, $content);
    break;

  case 'status':
    // show attendee status
    $content = rsvp_attendee_status($hash);
    break;

  case 'remove':
    // attempt to remove an attendee
    $rsvp = rsvp_load($invite->rid);
    $content = drupal_get_form('rsvp_attendee_confirm_remove', $hash, $rsvp->nid, $rsvp->rid);
    break;
  }

  return $content;
}

/**
* Displays an html formatted rsvp
*
* @ingroup rsvp_view
* @param $rsvp The rsvp to display.
* @return html formatted view of the requested rsvp instance.
*/
function rsvp_view($rid) {
  $rsvp = rsvp_load($rid);
  $node = node_load($rsvp->nid);
  if ($node->nid) {
    $content = theme('rsvp_event', $node);
  }
  $content .= '<h3>'. t('Invite Message') .'</h3>'. $rsvp->invite_text;

  return theme('rsvp', $rsvp, $content);
}

/**
* Displays html formatted attendees of an rsvp instance
*
* @ingroup rsvp_view
* @param $rid The rid of the rsvp instance.
* @param $controls Boolean that disables attendee control links. Default - enabled..
* @return html formatted view of the requested invite instance.
*/
function rsvp_show_attendees($rsvp, $controls = TRUE) {
  $content = '<h2>'. t('Responses') .'</h2>';
  $content .= l(t('Download RSVP List'), 'node/'. $rsvp->nid .'/rsvp/'. $rsvp->rid .'/attendees/csv');
  $content .= '<br /><br />';
  if ($rsvp->blind && !_rsvp_is_owner($rsvp->rid)) {
    // for blind rsvps display only totals
    $totals = _rsvp_attendance_totals($rsvp->rid);
    foreach ($totals as $key => $value) {
      if ($value) {
        $list[] = $key .': '. $value;
      }
    }
    $content .= theme('item_list', $list);
  }
  else {
    // display full attendee info
    $attendees = _rsvp_get_attendees($rsvp->rid);
    while ($attendee = db_fetch_object($attendees)) {
      if ($attendee->uid) {
        $u = db_fetch_object(db_query("SELECT uid, name FROM {users} WHERE uid = %d", $attendee->uid));
        $name = l($u->name, 'user/'. $u->uid, array('title' => t('view user')));
      }
      else {
        // hide e-mails for system users
        $user = user_load(array('uid' => $attendee->uid));
        $user_name = ($user->uid == 0 ? $attendee->email : $user->name);
        $name = ($controls ? $user_name : substr($attendee->email, 0, strpos($attendee->email, '@')));
      }

      $links = array();
      if ($controls) {
        $links['status'] = array(
          'title' => t('status'),
          'href' => 'rsvp/email/'. $attendee->hash .'/status',
          'attributes' => array('title' => t('view user invite status'))
        );
        $links['remove'] = array(
          'title' => t('remove'), 
          'href' => 'rsvp/email/'. $attendee->hash .'/remove', 
          'attributes' => array('title' => t('remove user from rsvp'))
        );
        $link = $name .' - '. theme('links', $links);
      }
      else {
        $link = $name;
      }

      if (!$attendee->invited) {
        $notsent[] = $link;
      }

      switch ($attendee->response) {
        case 'none' :
            $noreply[] = $link;
          break;
        case 'yes' :
            $yes[] = $link;
          break;
        case 'no' :
            $no[] = $link;
          break;
        case 'maybe' :
            $maybe[] = $link;
          break;
      }
    }

    if ($controls && $notsent) {
      $title = t('No invitation sent').' ['.l(t('Send invites'), 'node/'. $rsvp->nid .'/rsvp/'. $rsvp->rid .'/attendees/send', array('title' => t('Send invititations to uninvited users'))).']';
      $content .= theme('item_list', $notsent, $title);
    }
    $content .= theme('item_list', $noreply, t('No response'));
    $content .= theme('item_list', $yes, t('Attending'));
    $content .= theme('item_list', $no, t('Not attending'));
    $content .= theme('item_list', $maybe, t('Might attend'));
  }

  return $content;
}

function rsvp_attendees($rid, $hash = NULL, $action = NULL) {
  $content = '';
  if (user_access('rsvp newsletters subscribers') && module_exists('simplenews')) {
    $content .= rsvp_list_simplenews($rid);
  }
  if (user_access('rsvp buddylist') && module_exists('buddylist')) {
    $content .= rsvp_list_buddylist($rid);
  }
  if (user_access('rsvp system users')) {
    $content .= rsvp_list_roles($rid);
  }
  $content .= drupal_get_form('rsvp_attendee_form', $rid);
  $content .= rsvp_show_attendees(rsvp_load($rid));
  return $content;
}

/**
* Displays html formatted attendee reply status for an invite
*
* @ingroup rsvp_view
* @param $hash The hash value of the invite.
* @return html formatted view of the requested invite status.
*/
function rsvp_attendee_status($hash) {
  $invite = _rsvp_get_invite($hash);
  $list[] = ($invite->invited ? t('Attendee has been invited') : t('Attendee has not been invited'));
  $list[] = ($invite->received ? t('Attendee has viewed the invitation') : t('Attendee has not viewed the invitation'));
  $list[] = t('Attendee response: %response', array('%response' => $invite->response));

  return theme('item_list', $list, $invite->email);
}

/**
* Displays the rsvp attendee editing form
*
* @ingroup rsvp_form
* @param $rid The id of the rsvp instance to edit.
* @return html formatted rsvp attendee edit form.
*/
function rsvp_attendee_form($rid) {
  $rsvp = rsvp_load($rid);
  drupal_set_title($rsvp->name);
  $form = array();
  $form['invite_list'] = array(
      '#type' => 'textarea',
      '#title' => t('Add Attendees'),
      '#default_value' => '',
      '#cols' => 60,
      '#rows' => 5,
      '#description' => t('Enter email addresses or usernames each in a separate line.')
      );
  $form['rid'] = array(
    '#type' => 'hidden',
    '#value' => $rid,
  );

  $form['op'] = array(
      '#type' => 'submit',
      '#value' => t('Send Invites'),
      );

  return $form;
}

function rsvp_attendee_form_validate($form_id, $edit) {
  if (!strlen(preg_replace('/\s+/', '', $edit['invite_list']))) {
    drupal_set_message(t('Attendees list is empty.'), 'error');
  }
}

function rsvp_attendee_form_submit($form_id, $edit) {
  $content = '';
  // attempt to add the list of e-mails
  $emails = rsvp_set_invites(trim($edit['invite_list']), $edit['rid']);
  // send RSVPs
  $status = _rsvp_mail_rsvp($edit['rid']);
  // theme the output
  $content .= theme('rsvp_send_status', array_merge($emails, $status));
  drupal_set_message($content);
}

function rsvp_attendee_confirm_remove($hash, $nid, $rid) {
  $invite = _rsvp_get_invite($hash);
  $form['nid'] = array(
    '#type' => 'hidden',
    '#value' => $nid,
  );
  $form['rid'] = array(
    '#type' => 'hidden',
    '#value' => $rid,
  );
  $form['hash'] = array(
    '#type' => 'hidden',
    '#value' => $hash,
  );
  return confirm_form($form, 
    t('Are you sure you want to remove?'),
    'node/'. $nid .'/rsvp/'. $rid .'/attendees',
    t('Removing an attendee will delete their responses and remove their access to their invitations to this RSVP.'),
    t('Remove Attendee'), t('Cancel')
  );
}

function rsvp_attendee_confirm_remove_submit($form_id, $edit) {
  $invite = _rsvp_get_invite($edit['hash']);
  // hide e-mails for system users
  $user = user_load(array('uid' => $invite->uid));
  $name = ($user->uid == 0 ? $invite->email : $user->name);
  drupal_set_message(t('The attendee !name has been removed.', array('!name' => theme('placeholder', $name))));
  _rsvp_remove_attendee($edit['hash']);
  return 'node/'. $edit['nid'] .'/rsvp/'. $edit['rid'] .'/attendees';
}

/**
 * Callback to display an attendee list as CSV file
 *  - Copied from CiviCRM (which was copied from phpMyAdmin) so it should be robust
 */
function rsvp_attendees_csv($rid) {
  //fields to export
  $field_list = array( 'response', 'email', 'invited', 'received' );

  $rsvp = rsvp_load($rid);
  $attendees = _rsvp_get_attendees($rid);
  $attendee = db_fetch_object($attendees);
  $header = array();
  $content = '';

  //get header row
  foreach ($attendee as $key => $value) {
    if (in_array( $key, $field_list ))
      $header[]  = $key;
  }

  $filename = str_replace(' ', '_', $rsvp->name) .'_'. date("Y-m-d") .'.csv';

  $now       = gmdate('D, d M Y H:i:s') .' GMT';
  $mime_type = 'text/x-csv';
  $ext       = 'csv';

  // send the write header statements to the browser
  header('Content-Type: '. $mime_type);
  header('Expires: '. $now);

  // lem9 & loic1: IE need specific headers
  $is_ie = strstr( $_SERVER['HTTP_USER_AGENT'], 'MSIE' );
  if ($is_ie) {
    header('Content-Disposition: inline; filename="'. $filename .'"');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
  }
  else {
    header('Content-Disposition: attachment; filename="'. $filename .'"');
    header('Pragma: no-cache');
  }

  $result = '';

  $seperator     = ',';
  $enclosed      = '"';
  $escaped       = $enclosed;
  $add_character = "\015\012";
  $print = true;
  $schema_insert = '';
  foreach ( $header as $field ) {
    if ($enclosed == '') {
        $schema_insert .= stripslashes($field);
    }
    else {
        $schema_insert .=
              $enclosed
            . str_replace($enclosed, $escaped . $enclosed, stripslashes($field))
            . $enclosed;
    }
    $schema_insert     .= $seperator;
  } // end while

  // need to add PMA_exportOutputHandler functionality out here, rather than
  // doing it the moronic way of assembling a buffer
  $out = trim(substr($schema_insert, 0, -1)) . $add_character;
  if ($print) {
    echo $out;
  }
  else {
    $result .= $out;
  }

  $i = 0;
  $fields_cnt = count($header);

  $attendees = _rsvp_get_attendees($rid);

  while ($row = db_fetch_object($attendees)) {
      $schema_insert = '';
      foreach ( $row as $j => $value ) {
        if (in_array($j, $field_list)) {
          if (!isset($value) || is_null($value)) {
            $schema_insert .= '';
          }
          else if ($value == '0' || $value != '') {
            // loic1 : always enclose fields
            $value = ereg_replace("\015(\012)?", "\012", $value);
            if ($enclosed == '') {
              $schema_insert .= $value;
            }
            else {
              $schema_insert .=
                    $enclosed
                  . str_replace($enclosed, $escaped . $enclosed, $value)
                  . $enclosed;
            }
          }
          else {
            $schema_insert .= '';
          }

          if ($j < $fields_cnt-1) {
            $schema_insert .= $seperator;
          }
        } //end in field_list
      } // end foreach

      $out = $schema_insert . $add_character;
      if ($print) {
        echo $out;
      }
      else {
        $result .= $out;
      }
      ++$i;

  } // end for
}

/**
 * Callback to send invitations to users already
 * in the invitation list.
 *
 */
function rsvp_attendees_send_invites($rid, $destination = NULL) {
  // send RSVPs
  $status = _rsvp_mail_rsvp($rid);
  // theme the output
  $content = theme('rsvp_send_status', $status);
  drupal_set_message($content);
  if ($destination != NULL) {
    drupal_goto($destination);
  }
}

/**
* Displays the rsvp send list message form.
*
* @ingroup rsvp_form
* @param $rid The id of the rsvp to send the message to.
* @return html formatted rsvp send list message form.
*/
function rsvp_message_form($rid, $hash = NULL) {
  $rsvp = rsvp_load($rid);
  drupal_set_title($rsvp->name);

  $form = array();
  $form['status'] =  array(
       '#type' => 'select',
       '#title' => t('Message audience'),
       '#default_value' => 'all',
       '#options' => array('all' => t('Entire RSVP List'), 'yes' => t('Attending'), 'no' =>  t('Not attending'), 'maybe' =>  t('Might attend'), 'none' =>  t('No reply')),
       );
  $form['subject'] = array(
      '#type' => 'textfield',
      '#title' => t('Message Subject'),
      '#default_value' => '',
      '#size' => 40,
      '#maxlength' => 40,
      '#description' => t('This is the subject for your email message')
      );
  $form['body'] = array(
      '#type' => 'textarea',
      '#title' => t('Message Body'),
      '#default_value' => '',
      '#cols' => 60,
      '#rows' => 5,
      '#description' => t('This is the body of the email message')
      );
  $form['rid'] = array(
      '#type' => 'hidden',
      '#value' => $rid
      );
  if (!is_null($hash)) {
    $form['hash'] = array(
        '#type' => 'hidden',
        '#value' => $hash
      );
  }

  $form['op'] = array(
      '#type' => 'submit',
      '#value' => t('Send Message'),
      );

  // make sure that we won't send to none:
  $attendees = _rsvp_get_attendees($rid);
  if (!db_num_rows($attendees)) {
    drupal_set_message(t('No invitees in this RSVP.'));
    $form['op']['#disabled'] = TRUE;
  }

  return $form;
}

function rsvp_message_form_submit($form_id, $edit) {
  global $user;
  $status = rsvp_send_message($edit);
  $content = theme('rsvp_send_status', $status);
  drupal_set_message($content);
}


/**
* Displays html formatted invite reply status information for a user's invite
*
* @ingroup rsvp_view
* @param $hash The hash value of the invite.
* @return html formatted view of the requested invite status.
*/
function rsvp_reply_form($hash) {
  $invite = _rsvp_get_invite($hash);
  $responses = array('yes' => t('Yes'), 'no' => t('No'), 'maybe' => t('Maybe'));
  if ($invite->response == 'none') {
    $responses['none'] = t('None');
  }

  $form = array();
  $form['invite_reply'] = array(
      '#type' => 'select',
      '#title' => t('Your Reply'),
      '#default_value' => $invite->response,
      '#options' => $responses,
      '#description' => t('Select your response to the invitation here.')
      );
  $form['hash'] = array(
      '#type' => 'hidden',
      '#value' => $hash
      );

  $form['op'] = array(
      '#type' => 'submit',
      '#value' => t('Reply')
      );

  return $form;
}

function rsvp_reply_form_submit($form_id, $edit) {
  global $user;

  drupal_set_message('Your response was saved.', 'status');
  db_query('UPDATE {rsvp_invite} SET response = \'%s\', invited = 1, received = 1 WHERE hash = \'%s\'', $edit['invite_reply'], $edit['hash']);
  if ($user->uid > 0) {
    drupal_goto('user/'. $user->uid .'/rsvp');
  }
}


/**
 * @defgroup rsvp_data_functions functions for rsvp data manipulation.
 */

function rsvp_addedit($edit) {
  // if the rsvp already exists
  if ($edit['rid']) {
   return rsvp_update($edit); 
  }
  else {
    $rid = rsvp_create($edit); 
    drupal_goto('node/'. $edit['nid'] .'/rsvp/'. $rid .'/attendees');
  }
}

/**
* Creates a new rsvp
*
* @ingroup rsvp_functions
* @param $edit The post data of the create rsvp form.
* @return int key id of the rsvp instance or -1 on failure.
*/
function rsvp_create($edit) {
  global $user;

  $fields[] = 'uid';
  $vals[] = $user->uid;
  $markers[] = "%d";

  $fields[] = 'timestamp';
  $vals[] = time();
  $markers[] = "%d";

  foreach (array('name', 'invite_text', 'invite_list', 'blind', 'list_email', 'allow_invite', 'nid') as $key) {
    if ($key != 'invite_list') {
      $fields[] = $key;
      $vals[] = $edit[$key];
      $markers[] = "'%s'";
    }
  }

  $rid = db_next_id('rsvp');
  $fields[] = 'rid';
  $vals[] = $rid;
  $markers[] = "%d";

  $sql = 'INSERT INTO {rsvp} ('. implode(", ", $fields) .') VALUES ('. implode(", ", $markers) .')';

  if (db_query($sql, $vals)) {
    return $rid;
  }
  else {
    drupal_set_message(t('There was an error creating the RSVP. Please try again'));
    return FALSE;
  }
}

/**
* Updates an rsvp
*
* @ingroup rsvp_functions
* @param $edit The post data of the update rsvp form.
* @return boolean true on success.
*/
function rsvp_update($edit) {
  $fields[] = 'timestamp = %d';
  $vals[] = time();

  foreach (array('name', 'invite_text', 'blind', 'list_email', 'allow_invite') as $key) {
    $fields[] = $key ." = '%s'";
    $vals[] = $edit[$key];
  }

  if (!$edit['rid']) {
    return FALSE;
  }
  else {
    $vals[] = $edit['rid'];
  }

  $vals[] = $rid;
  
  $sql = 'UPDATE {rsvp} SET '. implode(', ', $fields) .' WHERE rid = %d';

  if (db_query($sql, $vals)) {
    drupal_set_message(t('RSVP updated.'));
    return TRUE;
  }
  else {
    drupal_set_message(t('There was an error updating the RSVP.'));
    return FALSE;
  }
}

/**
* Displays the rsvp editing form
*
* @ingroup rsvp_form
* @param $rid The id of the rsvp instance to edit.
* @return html formatted rsvp edit form.
*/
function rsvp_addedit_form($nid = NULL, $rid = NULL) {
  if (!is_null($rid)) {
    $rsvp = rsvp_load($rid);
    drupal_set_title($rsvp->name);
  }
  else {
    $rsvp = new stdClass();
  }

  $form['name'] = array(
      '#type' => 'textfield',
      '#title' => t('RSVP Name'),
      '#default_value' => $rsvp->name,
      '#size' => 40,
      '#maxlength' => 40,
      '#description' => t('This is the name of your RSVP.')
      );
  $form['invite_text'] = array(
      '#type' => 'textarea',
      '#title' => t('RSVP Message'),
      '#default_value' => $rsvp->invite_text,
      '#cols' => 60,
      '#rows' => 10,
      '#description' => t('This text will be sent to the people you invite.')
      );
  $form['blind'] = array(
      '#type' => 'checkbox',
      '#title' => t('Hide attendees'),
      '#return_value' => 1,
      '#default_value' => $rsvp->blind,
      '#description' => t('Prevent attendees from seeing who else is on the list.')
      );
  $form['list_email'] = array(
      '#type' => 'checkbox',
      '#title' => t('Allow list email'),
      '#return_value' => 1,
      '#default_value' => $rsvp->list_email,
      '#description' => t('Allow attendees to send messages to the people invited to your RSVP.')
      );
  $form['allow_invite'] = array(
      '#type' => 'checkbox',
      '#title' => t('Allow attendee invites'),
      '#return_value' => 1,
      '#default_value' => $rsvp->allow_invite,
      '#description' => t('Allow attendees to invite more people to the event')
      );
  $form['rid'] = array(
      '#type' => 'hidden',
      '#value' => $rsvp->rid
      );
  $form['nid'] = array(
      '#type' => 'hidden',
      '#value' => $nid
      );

  $form['update'] = array(
      '#type' => 'submit',
      '#value' => t('Submit'),
      '#name' => 'op'
      );
  if ($rid) {
    $form['delete'] = array(
        '#type' => 'submit',
        '#value' => t('Delete'),
        '#name' => 'op'
        );
  }
  return $form;
}

/**
* Handles submitting of the rsvp edit form
*
* @ingroup rsvp_form
* @param $form_id The id of the form submitted.
* @param $edit The $edit array.
* @return path a path to redirect after the form submission.
*/
function rsvp_addedit_form_submit($form_id, &$edit) {
  if ($edit['op'] == t('Delete')) {
    return 'node/'. $edit['nid'] .'/rsvp/'. $edit['rid'] .'/delete';
  }
  elseif ($edit['op'] == t('Submit')) {
    rsvp_addedit($edit);
    return 'node/'. $edit['nid'] .'/rsvp/'. $edit['rid'] .'/view';
  }
}


/**
* Deletes an rsvp
*
* @ingroup rsvp_functions
* @param $rid The rid of the rsvp to delete.
* @return boolean true on success.
*/
function rsvp_delete($rid) {
  if (db_query('DELETE FROM {rsvp} WHERE rid = %d', $rid)) {
    if (db_query('DELETE FROM {rsvp_invite} WHERE rid = %d', $rid)) {
      return RSVP_DELETED;
    }
    else {
      return RSVP_ERROR_DELETE_USER_RECORDS;
    }
  }
  else {
    return RSVP_ERROR_DELETE_RSVP;
  }
}
/**
* Displays the rsvp delete are you sure form
*
* @ingroup rsvp_form
* @param $rsvp The rsvp instance to confirm deletion for.
* @return html formatted rsvp delete confirmation form.
*/
function rsvp_delete_form($rid) {
  $rsvp = rsvp_load($rid);
  if (!$rsvp->rid) {
    drupal_set_message(t('The rsvp you requested does not exist.'));
    drupal_goto('rsvp/manage');
  }

  $form = array();
  $form['rid'] = array(
    '#type' => 'hidden',
    '#value' => $rsvp->rid,
  );
  $form['nid'] = array(
    '#type' => 'hidden',
    '#value' => $rsvp->nid,
  );
  return confirm_form($form,
      t('Are you sure you want to delete %name?', array('%name' => $rsvp->name)),
      'rsvp/'. check_url(arg(1)) .'/edit',
      t('This action cannot be undone.'),
      t('Delete'), t('Cancel'));
}

/**
* Handles submitting of the rsvp delete confirmation form
*
* @ingroup rsvp_form
* @param $form_id The id of the form submitted.
* @param $edit The $edit array.
* @return path a path to redirect after the form submission.
*/
function rsvp_delete_form_submit($form_id, &$edit) {
  switch (rsvp_delete($edit['rid'])) {
  case RSVP_DELETED:
    drupal_set_message(t('RSVP deleted.'));
    break;
  case RSVP_ERROR_DELETE_USER_RECORDS:
    drupal_set_message(t('There was an error removing the RSVP user records'));
    break;
  case RSVP_ERROR_DELETE_RSVP:
    drupal_set_message(t('There was an error removing the RSVP'));
    break;
  }
  return 'node/'. $edit['nid'] .'/rsvp';
}


/**
 * A wrapper to drupal_mail, just to unify e-mails
 * sent from RSVP module
 *
 * @ingroup rsvp_mail
 *
 * @param $mailkey
 *   A key to identify the mail sent, for altering.
 * @param $to
 *   The mail address or addresses where the message will be send to. The
 *   formatting of this string must comply with RFC 2822. Some examples are:
 *    user@example.com
 *    user@example.com, anotheruser@example.com
 *    User <user@example.com>
 *    User <user@example.com>, Another User <anotheruser@example.com>
 * @param $subject
 *   Subject of the e-mail to be sent. This must not contain any newline
 *   characters, or the mail may not be sent properly.
 * @param $body
 *   Message to be sent. Drupal will format the correct line endings for you.
 * @param $from
 *   Sets From, Reply-To, Return-Path and Error-To to this value, if given.
 * @param $headers
 *   Associative array containing the headers to add. This is typically
 *   used to add extra headers (From, Cc, and Bcc).
 *   <em>When sending mail, the mail must contain a From header.</em>
 * @return Returns TRUE if the mail was successfully accepted for delivery,
 *   FALSE otherwise.
 */
function rsvp_mail($mailkey, $to, $subject, $body, $from = NULL, $headers = array()) {
  $site_name = variable_get('site_name', 'drupal');
  $headers = array_merge(
    $headers, array(
      'Content-Type' => 'text/html; charset=UTF-8; format=flowed',
    )
  );
  return drupal_mail($mailkey, $to, $subject, $body, $from, $headers);
}

/**
* Sends an email.
*
* @ingroup rsvp_mail
* @param $invite The invite object to send the mail with.
* @return boolean. True if mail is successfully sent.
*/
function rsvp_send_invitation($invite, $from = NULL) {
  if (is_null($from)) {
    global $user;
    $from = $user->name .' <'. $user->mail .'>';
  }
  $subject = theme('rsvp_invite_mail_subject', $invite);
  $to = $invite->email;
  $body = theme('rsvp_invite_mail', $invite);
  return rsvp_mail('rsvp_invite_email', $to, $subject, $body, $from);
}

/**
* Emails a message to the attendees of an rsvp instance.
*
* @ingroup rsvp_mail
* @param $edit The send message form post data.
* @return string of formatted recipients, or empty string depending on $confirm.
*/
function rsvp_send_message($edit) {
  // check whether the message is sent from a user who's invited
  // yet allowed to message other attendees
  if (!$edit['hash'] || is_null($edit['hash'])) {
    global $user;
    $sender = $user->name;
    $from = $user->name .' <'. $user->mail .'>';
  }
  else {
    $inviter = _rsvp_get_invite($edit['hash']);
    $sender = $inviter->email;
    $from = $inviter->email;
  }
  $site = variable_get("site_name", "drupal");
  $subject = $edit['subject'];

  $status['success'] = array();
  $status['failed'] = array();

  $attendees = _rsvp_get_attendees($edit['rid']);
  while ($attendee = db_fetch_object($attendees)) {
    $invite = _rsvp_get_invite($attendee->hash);

    $body = t("Hello!\n\nYou have been sent a message by !sender at !site.\n\nYou can view the invitation from where it originated by following this link: \n!url\n\nHere is the message:\n", array('!sender' => $sender, '!site' => $site, '!url' => url("rsvp/email/$invite->hash", NULL, NULL, 1))) . $edit['body'];

    $to = $attendee->email;
    if (rsvp_mail('rsvp_message_mail', $to, $subject, $body, $from)) {
      $status['success'][$invite->email] = substr($invite->email, 0, strpos($invite->email, '@'));
    }
    else {
      $status['failed'][$invite->email] = substr($invite->email, 0, strpos($invite->email, '@'));
    }
  }

  return $status;
}

/**
 * Returns a list of members of newsletters created with Simplenews module.
 *
 * @param $rid int The RSVP ID.
 * @return string List of members.
 */
function rsvp_list_simplenews($rid) {
  if (module_exists('simplenews')) {
    $rsvp = rsvp_load($rid);
    $content = t('<h3>You may invite people subscribed to newsletters:</h3>');
    $rows = array();
    $header = array(t('Newsletter name'), array('data' => t('Operations')));

    foreach (taxonomy_get_tree(_simplenews_get_vid()) as $term) {
      $rows[] = array(
        $term->name,
        l(t('Add'), 'node/'. $rsvp->nid .'/rsvp/'. $rsvp->rid .'/attendees/simplenews/'. $term->tid, 
        array('onclick' => "$.get($(this).attr('href'), function(data){ $('#edit-invite-list').val(data); }); return false;")),
      );
    }

    if (count($rows) == 0) {
      $rows[] = array(array('data' => t('There are currently no newsletter series.'), 'colspan' => 2));
    }
    $content .= theme('table', $header, $rows);
    return $content;
  }
}

/**
 * Returns a list of system roles.
 *
 * @param $rid int The RSVP ID.
 * @return string a list of system roles.
 */
function rsvp_list_roles($rid) {
  $rsvp = rsvp_load($rid);
  $content = t('<h3>You may invite site users:</h3>');
  $rows = array();
  $header = array(t('Role'), array('data' => t('Operations')));

  foreach (user_roles(TRUE) as $rid => $role) {
    $rows[] = array(
      $role,
      l(t('Add'), 'node/'. $rsvp->nid .'/rsvp/'. $rsvp->rid .'/attendees/role/'. $rid, 
      array('onclick' => "$.get($(this).attr('href'), function(data){ $('#edit-invite-list').val(data); }); return false;")),
    );
  }

  $content .= theme('table', $header, $rows);
  return $content;
}

/**
 * Returns user's buddylist.
 *
 * @param $uid int The RSVP ID.
 * @return string The user's buddylist.
 */
function rsvp_list_buddylist($rid) {
  global $user;
  $rsvp = rsvp_load($rid);
  $content = t('<h3>You may invite your buddylist:</h3>');
  $rows = array();
  $header = array(t('Buddy'), array('data' => t('Operations')));

  $query = db_query("SELECT DISTINCT(b.buddy), u.name FROM {buddylist} b INNER JOIN {users} u ON b.buddy = u.uid WHERE b.uid = %d ORDER BY u.name ASC", $user->uid);

  while ($buddy = db_fetch_object($query)) {
    $rows[] = array(
      $buddy->name,
      l(t('Add'), NULL, 
      array('onclick' => '$("#edit-invite-list").val($("#edit-invite-list").val() + "'. $buddy->name .'\r\n"); return false;'),
      NULL,
      'add'
    ),
    );
  }

  $content .= theme('table', $header, $rows);
  return $content;

}

/**
 * Returns a list of newsletter subscribers.
 *
 * @param $nlid int The newsletter ID.
 * @return string list of subscribers.
 */
function rsvp_attendees_simplenews($nlid) {
  $subs = "";
  $query = db_query('SELECT DISTINCT s.mail FROM {simplenews_subscriptions} s INNER JOIN simplenews_snid_tid t ON s.snid = t.snid WHERE t.tid = %d ORDER BY mail ASC', $nlid);
  while ($sub = db_fetch_object($query)) {
    $subs .= $sub->mail ."\r\n";
  }
  print $subs;
  exit();
}

/**
 * Returns a list of users in a specific role.
 *
 * @param $rid int The role ID.
 * @return string list of users.
 */
function rsvp_attendees_users($rid) {
  if (is_numeric($rid)) {
    $subs = "";
    // if the requested role is authenticated, no records will be returned from
    // normal query
    if ($rid == 2) {
      $query = db_query('SELECT name FROM {users} ORDER BY uid DESC');
    }
    else {
      $query = db_query('SELECT name FROM {users} u INNER JOIN {users_roles} ur ON u.uid = ur.uid WHERE ur.rid = %d ORDER BY u.uid DESC', $rid);
    }
    while ($u = db_fetch_object($query)) {
      $subs .= $u->name ."\r\n";
    }
    print $subs;
    exit();
  }
}

/**
* Returns the rsvps that a user is the owner of.
*
* @ingroup rsvp_functions
* @param $uid The uid of the user.
* @return dbresultset of rsvps.
*/
function _rsvp_get_rsvps($nid = NULL, $uid = NULL, $tablesort = ' ORDER BY nid') {
  if (!$uid) {
    global $user;
    $uid = $user->uid;
  }
  $query = 'SELECT r.*, n.title FROM {rsvp} r INNER JOIN {node} n ON r.nid = n.nid WHERE r.uid = %d';
  if (!is_null($nid)) {
    if (is_array($nid)) {
      $query .= ' AND r.nid IN (%s)';
      $nid = implode(', ', $nid);
    }
    elseif (is_numeric($nid)) {
      $query .= ' AND r.nid = %d';
    }
  }
  $query .= $tablesort;
  return db_query($query, $uid, $nid);
}

/**
* Returns the invites that a user has received.
*
* @ingroup rsvp_functions
* @param $uid The uid of the user.
* @return array of event nids.
*/
function _rsvp_get_invites($uid = NULL) {
  if (!$uid) {
    global $user;
    $uid = $user->uid;
  }
  return db_query('SELECT * FROM {rsvp} r LEFT JOIN {rsvp_invite} u ON r.rid = u.rid WHERE u.uid = %d', $uid);
}

/**
* Returns an invite by hash value.
*
* @ingroup rsvp_functions
* @param $hash The hash value of the invite.
* @return dbresultset of the requested invite.
*/
function _rsvp_get_invite($hash) {
  return db_fetch_object(db_query('SELECT * FROM {rsvp} r LEFT JOIN {rsvp_invite} u ON r.rid = u.rid WHERE u.hash = \'%s\'', $hash));
}

/**
* Returns the invites that a user has received for a specific event node.
*
* @ingroup rsvp_functions
* @param $nid The nid of the node.
* @param $uid The uid of the user.
* @return array of event nids.
*/
function _rsvp_get_node_invites($nid, $uid = NULL) {
  if (!$uid) {
    global $user;
    $uid = $user->uid;
  }
  return db_query('SELECT * FROM {rsvp} r LEFT JOIN {rsvp_invite} u ON r.rid = u.rid WHERE u.uid = %d AND r.nid = %d', $uid, $nid);
}

/**
* Returns an rsvp's attendees
*
* @ingroup rsvp_functions
* @param $rid The rid of the rsvp instance.
* @return dbresultset of the requested attendees.
*/
function _rsvp_get_attendees($rid, $status = 'all') {
  if ($status == 'all' || !isset($status))
    return db_query('SELECT * FROM {rsvp_invite} WHERE rid = %d', $rid);
  else
    return db_query('SELECT * FROM {rsvp_invite} WHERE rid = %d and response=\'%s\'', $rid, $status);
}

/**
* Returns an rsvp's attendee response totals
*
* @ingroup rsvp_functions
* @param $rid The rid of the rsvp instance.
* @return dbresultset of the requested attendees.
*/
function _rsvp_attendance_totals($rid) {
  $responses = array(t('No Response') => 'none', t('Yes') => 'yes', t('No') => 'no', t('Maybe') => 'maybe');
  foreach ($responses as $key => $response) {
    $total = db_fetch_object(db_query('SELECT count(*) as total FROM {rsvp_invite} WHERE rid = %d AND response = \'%s\'', $rid, $response));
    $totals[$key] = $total->total;
  }
  return $totals;
}

/**
* Removes an rsvp's attendee
*
* @ingroup rsvp_functions
* @param $hash The hash key value of the rsvp attendee.
* @return boolean true if successful.
*/
function _rsvp_remove_attendee($hash) {
  return db_query('DELETE FROM {rsvp_invite} WHERE hash = \'%s\'', $hash);
}

/**
* Checks if an email address already exists for an rsvp.
*
* @ingroup rsvp_functions
* @param $rid The id of the rsvp.
* @param $email The email to check for.
* @return boolean true if the email exists for the rsvp.
*/
function _rsvp_attendee_exists($rid, $email) {
  if (db_num_rows(db_query('SELECT uid FROM {rsvp_invite} WHERE rid = %d AND email = \'%s\'', $rid, $email)) > 0) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

/**
* Checks to see if a user has been invited to an event.
*
* @ingroup rsvp_functions
* @param $nid The node id of the event.
* @param $uid The uid of the user. If null, it uses global $user->uid.
* @return boolean. True if user has been invited to the event.
*/
function _rsvp_is_invited($nid, $uid = NULL) {
  if (!$uid) {
    global $user;
    if ($user->uid) {
      $uid = $user->uid;
    }
    else {
      return FALSE;
    }
    
  }

  if (db_num_rows(db_query('SELECT u.uid FROM {rsvp} r LEFT JOIN {rsvp_invite} u ON r.rid = u.rid WHERE r.nid = %d AND u.uid = %d', $nid, $uid)) > 0) {
    return TRUE;
  }
  return FALSE;
}

/**
* Checks to see if an rsvp is blind has been invited to an event.
*
* @ingroup rsvp_functions
* @param $rid The rid of the rsvp.
* @return boolean. False if the rsvp is blind.
*/
function _rsvp_is_blind($rid) {
  $status = db_fetch_object(db_query('SELECT blind FROM {rsvp} WHERE rid = %d', $rid));

  return $status->blind;
}

/**
* Checks to see if a user is the owner of an rsvp.
*
* @ingroup rsvp_functions
* @param $rid The id of the rsvp.
* @param $uid The uid of the user. If null, it uses global $user->uid.
* @return boolean. True if user is the owner of an rsvp to the event.
*/
function _rsvp_is_owner($rid, $uid = NULL) {

  if (!$uid) {
    global $user;
    $uid = $user->uid;
  }
  if (db_num_rows(db_query('SELECT uid FROM {rsvp} WHERE rid = %d AND uid = %d', $rid, $uid)) > 0) {
    return TRUE;
  }
  return FALSE;
}

/**
* Checks to see if a user is the owner of an rsvp for an event node.
*
* @ingroup rsvp_functions
* @param $nid The id of the event node.
* @param $uid The uid of the user. If null, it uses global $user->uid.
* @return boolean. True if user is the owner of an rsvp to the event.
*/
function _rsvp_has_rsvps($nid, $uid = NULL) {
  if (!$uid) {
    global $user;
    $uid = $user->uid;
  }
  if (db_num_rows(db_query('SELECT uid FROM {rsvp} WHERE nid = %d AND uid = %d', $nid, $uid)) > 0) {
    return TRUE;
  }
  return FALSE;
}

/**
* Checks to see if an rsvp has enabled attendee invite sending.
*
* @ingroup rsvp_functions.
* @param $rid The id of the rsvp.
* @return boolean. True if rsvp allows attendee invite sending.
*/
function _rsvp_is_invite_viral($rid) {
  $viral = db_fetch_object(db_query('SELECT allow_invite FROM {rsvp} WHERE rid = %d', $rid));

  return $viral->allow_invite;
}

/**
* Checks to see if an rsvp has enabled attendee list message sending.
*
* @ingroup rsvp_functions.
* @param $rid The id of the rsvp.
* @return boolean. True if rsvp allows attendee list message sending.
*/
function _rsvp_is_invite_message_enabled($rid) {
  $enabled = db_fetch_object(db_query('SELECT list_email FROM {rsvp} WHERE rid = %d', $rid));

  return $enabled->list_email;
}

/**
 * @defgroup rsvp_mail functions for rsvp mailing.
 */

/**
* Emails the invite to the attendees of an rsvp instance.
*
* @ingroup rsvp_mail
* @param $rid The rid of the rsvp.
* @param $resend True: sends only to recipients with received flag not set. default: false.
* @return array of status values.
*/
function _rsvp_mail_rsvp($rid, $from = NULL, $resend = FALSE) {
  $status['success'] = array();
  $status['failed'] = array();
  $attendees = _rsvp_get_attendees($rid);
  while ($attendee = db_fetch_object($attendees)) {
    if (!($resend && $attendee->received) && !($attendee->invited)) {
      $invite = _rsvp_get_invite($attendee->hash);
      if (rsvp_send_invitation($invite, $from)) {
        db_query('UPDATE {rsvp_invite} SET invited = 1 WHERE hash = \'%s\'', $attendee->hash);
        // hide e-mails for system users
        $user = user_load(array('uid' => $attendee->uid));
        $status['success'][] = ($user->uid == 0 ? $invite->email : $user->name);
      }
      else {
        // hide e-mails for system users
        $user = user_load(array('uid' => $attendee->uid));
        $status['failed'][] = ($user->uid == 0 ? $invite->email : $user->name);
      }
    }
  }
  return $status;
}

/**
 * Provides a link to the CSS stylesheet associated with this module.
 *
 * @ingroup rsvp_core
 * @return a &lt;style&gt; tag that indicates what file browsers should import
 */
function _rsvp_html_head() {
  drupal_add_css(drupal_get_path('module', 'rsvp') .'/rsvp.css');
}

?>