You are here

forward.module in Forward 7.2

File

forward.module
View source
<?php

/**
 * @file
 * Allows forwarding of nodes by email,
 * and provides a record of how often each has been forwarded.
 *
 * Forward This Page Module
 *
 * Drupal 6 version:
 * Written by Sean Robertson
 * http://www.ngpsoftware.com
 *
 * Customized by development seed
 * http://www.developmentseed.org
 *
 * Drupal 7 version:
 * Written by John Oltman
 * http://sitebasin.com
 *
 */
include DRUPAL_ROOT . '/' . drupal_get_path('module', 'forward') . '/forward.theme';

/**
 * Implements hook_permission().
 */
function forward_permission() {
  return array(
    'access forward' => array(
      'title' => t('access forward'),
      'description' => t('Forward pages'),
    ),
    'access epostcard' => array(
      'title' => t('access epostcard'),
      'description' => t('Send epostcards'),
    ),
    'override email address' => array(
      'title' => t('override email address'),
      'description' => t('Override email address'),
    ),
    'administer forward' => array(
      'title' => t('administer forward'),
      'description' => t('Administer forward'),
    ),
    'override flood control' => array(
      'title' => t('override flood control'),
      'description' => t('Bypass flood control check'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function forward_menu() {
  $items = array();
  $items['epostcard'] = array(
    'title' => variable_get('forward_epostcard_title', 'Send an e-Postcard'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'forward_form',
      'epostcard',
    ),
    'access arguments' => array(
      'access epostcard',
    ),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['admin/reports/forward'] = array(
    'description' => 'Track forwarded posts',
    'title' => 'Forward tracking',
    'page callback' => 'forward_tracking',
    'access arguments' => array(
      'administer forward',
    ),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['forward/emailref'] = array(
    'title' => 'Track email clickthrus',
    'page callback' => 'forward_tracker',
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['forward'] = array(
    'title' => variable_get('forward_email_title', 'Forward this page to a friend'),
    'page callback' => 'forward_page',
    'access arguments' => array(
      'access forward',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/user-interface/forward'] = array(
    'description' => 'Configure settings for forward module.',
    'title' => 'Forward',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'forward_admin_settings',
    ),
    'access arguments' => array(
      'administer forward',
    ),
    'file' => 'forward.admin.inc',
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}

/**
 * Callback function for the Email Tracker
 */
function forward_tracker() {
  global $user;
  $form_state['values']['path'] = drupal_get_normal_path($_GET['path']);
  $args = explode('/', $form_state['values']['path']);
  if (!isset($form_state['values']['path']) || $form_state['values']['path'] == variable_get('site_frontpage', 'node')) {
    $form_state['values']['path'] = '<front>';
  }

  // Flood control - only allow a certain number of tracking events per minute per IP address
  if (flood_is_allowed('forward_tracker', variable_get('forward_flood_control_clicks', 3), 60)) {
    if ($args[0] == 'node' && !empty($args[1]) && is_numeric($args[1])) {
      $nid = $args[1];
      db_update('forward_statistics')
        ->expression('clickthrough_count', 'clickthrough_count + 1')
        ->condition('nid', $nid)
        ->execute();
    }
    $id = db_insert('forward_log')
      ->fields(array(
      'path' => $form_state['values']['path'],
      'type' => 'REF',
      'timestamp' => REQUEST_TIME,
      'uid' => $user->uid,
      'hostname' => ip_address(),
    ))
      ->execute();
  }
  flood_register_event('forward_tracker', 60);
  if (!url_is_external($form_state['values']['path'])) {
    drupal_goto(drupal_get_path_alias($form_state['values']['path']));
  }
  else {
    drupal_goto();
  }
}

/**
 * Implements hook_ctools_plugin_directory().
 *
 */
function forward_ctools_plugin_directory($module, $plugin) {

  // Tell Panels where our plugin is
  if ($module == 'ctools' && !empty($plugin)) {
    return "plugins/{$plugin}";
  }
}

/**
 * Implements hook_ds_fields_info().
 */
function forward_ds_fields_info($entity_type) {
  $fields = array();
  if ($entity_type == 'node') {
    $ui_limit = array();
    $bundles = node_type_get_types();
    foreach ($bundles as $type => $bundle) {
      if (variable_get('forward_display_' . $type, TRUE)) {
        $ui_limit[] = $type . '|*';
      }
    }
    $fields['node'] = array();
    $fields['node']['forward_ds_field'] = array(
      'title' => t('Forward link'),
      'field_type' => DS_FIELD_TYPE_FUNCTION,
      'function' => 'forward_ds_field_create',
      'ui_limit' => $ui_limit,
    );
  }
  return $fields;
}

/**
 * Callback for Display Suite field.
 */
function forward_ds_field_create($field) {
  $output = '';
  if (user_access('access forward')) {
    $node = $field['entity'];
    if (variable_get('forward_display_' . $node->type, 1)) {
      $output = theme('forward_link', array(
        'node' => $node,
      ));
    }
  }
  return $output;
}

/**
 * Theme function for Forward link
 */
function theme_forward_link($variables) {
  $node = isset($variables['node']) ? $variables['node'] : NULL;
  $path = isset($variables['path']) ? $variables['path'] : NULL;
  $block = isset($variables['block']) ? $variables['block'] : FALSE;

  // Handle a node path (node/nid) with no node
  if (!$node && $path) {
    $args = explode('/', $path);
    if (count($args) == 2 && $args[0] == 'node' && is_numeric($args[1])) {
      $node = node_load($args[1]);
    }
  }

  // Generate the link unless given a bad path
  $output = '';
  if (!$path || !url_is_external($path)) {
    $link = forward_link_create($node, $path, $block);
    $output = $link['content'];
  }
  return $output;
}

/**
 * Generate a Forward link for a node or page
 */
function forward_link_create($node = NULL, $path = NULL, $block = FALSE) {
  drupal_add_css(drupal_get_path('module', 'forward') . '/forward.css');
  if ($node) {
    $forward_link_type = variable_get('forward_link_type', 0) ? node_type_get_name($node->type) : t('page');
  }
  else {
    $forward_link_type = t('page');
  }
  $title = check_plain(t(variable_get('forward_link_title', 'Email this !type'), array(
    '!type' => $forward_link_type,
  )));
  $html = FALSE;

  // Always include some text for the block link
  $link_style = variable_get('forward_link_style', 0);
  if ($block && $link_style == 1) {
    $link_style++;
  }

  // Output the correct style of link
  $default_icon = drupal_get_path('module', 'forward') . '/forward.gif';
  $custom_icon = variable_get('forward_link_icon', '');
  switch ($link_style) {

    // text only is a "noop" since the title text is already setup above
    // image only
    case 1:
      $img = $custom_icon ? $custom_icon : $default_icon;
      $title = theme('image', array(
        'path' => $img,
        'alt' => $title,
        'attributes' => array(
          'class' => array(
            'forward-icon',
          ),
        ),
      ));
      $html = TRUE;
      break;

    // image and text
    case 2:
      $img = $custom_icon ? $custom_icon : $default_icon;
      $tag = theme('image', array(
        'path' => $img,
        'alt' => $title,
        'attributes' => array(
          'class' => array(
            'forward-icon',
            'forward-icon-margin',
          ),
        ),
      ));
      $title = $tag . $title;
      $html = TRUE;
      break;
  }
  if ($node) {
    if (variable_get('forward_link_alias', 0)) {
      $path = drupal_get_path_alias('node/' . $node->nid, $node->language);
    }
    else {
      $path = 'node/' . $node->nid;
    }
  }
  else {
    if (!$path) {
      $path = $_GET['q'];
    }
    if (variable_get('forward_link_alias', 0)) {
      $path = drupal_get_path_alias($path);
    }
  }
  $attributes = array(
    'title' => variable_get('forward_email_title', t('Forward this page to a friend')),
    'class' => array(
      'forward-page',
    ),
  );
  if (variable_get('forward_colorbox_enable', 0)) {
    if (module_exists('colorbox_node')) {
      $overlay = 'cboxnode';
      $attributes['class'][] = 'colorbox-node';
    }
    else {
      $overlay = 'cbox';
      $attributes['class'][] = 'colorbox-load';
    }
    $query = array(
      'path' => $path,
      'overlay' => $overlay,
      'width' => variable_get('forward_colorbox_width', 600),
      'height' => variable_get('forward_colorbox_height', 600),
    );
  }
  else {
    $query = array(
      'path' => $path,
    );
  }
  if (variable_get('forward_link_nofollow', 0)) {
    $attributes['rel'] = 'nofollow';
  }
  $content = l($title, 'forward', array(
    'html' => $html,
    'attributes' => $attributes,
    'query' => $query,
  ));
  return array(
    'content' => $content,
    'title' => $title,
    'html' => $html,
    'attributes' => $attributes,
    'query' => $query,
  );
}

/**
 * Callback function for the forward Page
 */
function forward_page() {

  // Tell SEO to ignore this page (but don't generate the meta tag for an overlay)
  if (variable_get('forward_link_noindex', 1) && !isset($_GET['overlay'])) {
    $element = array(
      '#type' => 'html_tag',
      '#tag' => 'meta',
      '#attributes' => array(
        'name' => 'robots',
        'content' => 'noindex, nofollow',
      ),
    );
    drupal_add_html_head($element, 'forward_meta_noindex');
  }

  // Get node or path being forwarded
  $nid = NULL;
  if (empty($_GET['path']) || $_GET['path'] == 'node/0') {
    return t('No path was selected to forward');
  }
  if (url_is_external($_GET['path'])) {
    return t('You cannot forward an external URL.');
  }
  if (!empty($_GET['path'])) {
    $form_state['values']['path'] = drupal_get_normal_path($_GET['path']);
    $ret = preg_match("/^node\\/(.*)/i", $form_state['values']['path'], $matches);
    if ($ret == 1) {
      $nid = $matches[1];
    }
  }
  if (is_numeric($nid)) {

    // we have a node
    $node = node_load($nid);
    if (!node_access('view', $node)) {

      // Access is denied
      return MENU_ACCESS_DENIED;
    }
    $form_state['values']['path'] = 'node/' . $node->nid;
  }
  else {
    $args = explode('/', $form_state['values']['path']);
    if ($args[0] == 'admin') {
      return MENU_ACCESS_DENIED;
    }
    $node = new stdClass();
    $node->title = $form_state['values']['path'];
  }
  if ($form_state['values']['path'] == 'epostcard') {
    $emailtype = 'postcard';
    drupal_set_title(t(variable_get('forward_epostcard_title', 'Send an e-Postcard')));
  }
  else {
    $emailtype = 'page';
    if (!empty($_GET['cid'])) {
      $cid = '?cid=' . $_GET['cid'];
      $form_state['values']['path'] .= $cid;
    }
    drupal_set_title(t(variable_get('forward_email_title', 'Forward this page to a friend')));
  }
  return theme('forward_' . $emailtype, array(
    'vars' => drupal_get_form('forward_form', $form_state['values']['path'], $node),
    'node' => $node,
  ));
}

/**
 * Callback function for the forward Form
 */
function forward_form($form, &$form_state, $path = NULL, $node = NULL, $nodeapi = FALSE) {
  global $base_url, $user;
  $emailtype = $path == 'epostcard' ? 'epostcard' : 'email';
  $cid = array();
  if (preg_match("/\\?cid=/i", $path) == 1) {
    $paths = explode('?cid=', $path);
    $cid = array(
      'fragment' => 'comment-' . $paths[1],
    );
    $path = $paths[0];
  }
  if (isset($node->type)) {
    $forward_link_type = variable_get('forward_link_type', 0) ? node_type_get_name($node->type) : t('page');
  }
  else {
    $forward_link_type = t('page');
  }
  if ($nodeapi == TRUE) {
    $form['message'] = array(
      '#type' => 'fieldset',
      '#title' => check_plain(t(variable_get('forward_link_title', 'Email this !type'), array(
        '!type' => $forward_link_type,
      ))),
      '#description' => '',
      '#collapsed' => TRUE,
      '#collapsible' => TRUE,
      '#weight' => 10,
    );
  }

  // Insert an H1 if for colorbox node overlay, otherwise the overlay appears without a title
  if (variable_get('forward_colorbox_enable', 0) && isset($_GET['overlay']) && $_GET['overlay'] == 'cboxnode') {
    $title = t(variable_get('forward_email_title', 'Forward this page to a friend'));
    $form['message']['extra_title'] = array(
      '#markup' => '<h1>' . $title . '</h1>',
    );
  }
  $form['message']['instructions'] = array(
    '#type' => 'item',
    '#markup' => filter_xss_admin(token_replace(t(variable_get('forward_instructions', '<p>Thank you for your interest in spreading the word on [site:name].</p><p>NOTE: We only request your email address so that the person you are recommending the page to knows that you wanted them to see it, and that it is not junk mail. We do not capture any email address.</p>')))),
  );
  $form['message']['email'] = array(
    '#type' => 'textfield',
    '#title' => t('Your Email'),
    '#size' => 58,
    '#maxlength' => 256,
    '#required' => TRUE,
  );
  $form['message']['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Your Name'),
    '#size' => 58,
    '#maxlength' => 256,
    '#required' => TRUE,
  );
  $form['message']['recipients'] = array(
    '#type' => 'textarea',
    '#title' => t('Send To'),
    '#cols' => 50,
    '#rows' => 5,
    '#description' => t('Enter multiple addresses on separate lines or separate them with commas.'),
    '#required' => TRUE,
  );
  if ($emailtype == 'email' && $nodeapi == FALSE && isset($node->title)) {
    $form['message']['page'] = array(
      '#type' => 'item',
      '#title' => t('You are going to email the following'),
      '#markup' => l($node->title, $path, $cid),
    );
  }
  if (isset($node->type)) {
    $form['message']['subject'] = array(
      '#type' => 'item',
      '#title' => t('Message Subject'),
      '#markup' => token_replace(t(variable_get('forward_' . $emailtype . '_subject', '[forward:sender] has sent you a message from [site:name]')), array(
        'forward' => array(),
        'node' => $node,
      )),
      '#description' => '',
    );
    $form['message']['body'] = array(
      '#type' => 'item',
      '#title' => t('Message Body'),
      '#markup' => token_replace(t(variable_get('forward_' . $emailtype . '_message', '[forward:sender] thought you would like to see the [site:name] web site.')), array(
        'forward' => array(),
        'node' => $node,
      )),
      '#description' => '',
    );
  }
  else {
    $form['message']['subject'] = array(
      '#type' => 'item',
      '#title' => t('Message Subject'),
      '#markup' => token_replace(t(variable_get('forward_' . $emailtype . '_subject', '[forward:sender] has sent you a message from [site:name]')), array(
        'forward' => array(),
      )),
      '#description' => '',
    );
    $form['message']['body'] = array(
      '#type' => 'item',
      '#title' => t('Message Body'),
      '#markup' => token_replace(t(variable_get('forward_' . $emailtype . '_message', '[forward:sender] thought you would like to see the [site:name] web site.')), array(
        'forward' => array(),
      )),
      '#description' => '',
    );
  }
  if (variable_get('forward_message', 1) != 0) {
    $form['message']['message'] = array(
      '#type' => 'textarea',
      '#title' => t('Your Personal Message'),
      '#default_value' => '',
      '#cols' => 50,
      '#rows' => 5,
      '#description' => '',
      '#required' => variable_get('forward_message', 1) == 2 ? TRUE : FALSE,
    );
  }
  $form['message']['path'] = array(
    '#type' => 'hidden',
    '#value' => $path,
  );
  $form['message']['path_cid'] = array(
    '#type' => 'hidden',
    '#value' => !empty($cid['fragment']) ? '#' . $cid['fragment'] : '',
  );
  $form['message']['forward_footer'] = array(
    '#type' => 'hidden',
    '#value' => variable_get('forward_footer', ''),
  );
  if ($nodeapi) {

    // When using a collapsible form on the node page, move submit button into fieldset
    $form['message']['actions'] = array(
      '#type' => 'actions',
    );
    $form['message']['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Send Message'),
    );
  }
  else {

    // When using a separate form page, use actions directly so Mollom knows where to place its content
    $form['actions'] = array(
      '#type' => 'actions',
    );
    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Send Message'),
    );
  }
  if ($user->uid != 0) {
    if (user_access('override email address')) {
      $form['message']['email']['#default_value'] = $user->mail;
    }
    else {
      $form['message']['email']['#type'] = 'hidden';
      $form['message']['email']['#value'] = $user->mail;
    }
    $form['message']['name']['#default_value'] = $user->name;
  }
  return $form;
}

/**
 * Implements hook_node_insert().
 */
function forward_node_insert($node) {
  $id = db_insert('forward_statistics')
    ->fields(array(
    'nid' => $node->nid,
    'last_forward_timestamp' => 0,
    'forward_count' => 0,
    'clickthrough_count' => 0,
  ))
    ->execute();
}

/**
 * Implements hook_node_delete().
 */
function forward_node_delete($node) {
  db_delete('forward_statistics')
    ->condition('nid', $node->nid)
    ->execute();
}

/**
 * Validation callback function for forward form submit
 */
function forward_form_validate($form, &$form_state) {
  global $base_url, $user;
  $url = $base_url . '/' . $form_state['values']['path'];

  // normalize address entries
  $tokens = forward_recipient_list($form_state);
  $recipient_addresses = $tokens['recipients'];
  $bad_items = array(
    'Content-Type:',
    'MIME-Version:',
    'Content-Transfer-Encoding:',
    'bcc:',
    'cc:',
  );
  $bad_string = FALSE;
  foreach ($bad_items as $item) {
    if (preg_match("/{$item}/i", $form_state['values']['email'])) {
      $bad_string = TRUE;
    }
  }
  if (strpos($form_state['values']['email'], "\r") !== FALSE || strpos($form_state['values']['email'], "\n") !== FALSE || $bad_string == TRUE) {
    form_set_error('email', t('Header injection attempt detected.  Do not enter line feed characters into the from field!'));
  }
  if (user_validate_mail($form_state['values']['email'])) {
    form_set_error('email', t('Your Email address is invalid.'));
  }
  if (!$form_state['values']['name']) {
    form_set_error('name', t('You must enter your name.'));
  }
  if (empty($recipient_addresses)) {
    form_set_error('recipients', t('You did not enter any recipients.'));
  }
  else {
    foreach ($recipient_addresses as $address) {
      if (user_validate_mail($address) && $address != '') {
        form_set_error('recipients', t('One of your Recipient addresses is invalid:') . '<br />' . check_plain($address));
      }
    }
  }
  if (!user_access('override flood control')) {

    // Check if it looks like we are going to exceed the flood limit.
    // It is important to ensure that the number of e-mails to be sent count against the threshold.
    if (!flood_is_allowed('forward', variable_get('forward_flood_control', 10) - count($recipient_addresses) + 1)) {
      form_set_error('recipients', check_plain(t(variable_get('forward_flood_error', "You can't send more than !number messages per hour. Please try again later."), array(
        '!number' => variable_get('forward_flood_control', 10),
      ))));
    }
  }
  if (variable_get('forward_message', 1) == 2 && empty($form_state['values']['message'])) {
    form_set_error('message', t('You must enter a message.'));
  }
}

/*
 * Create a forward receipients list and token
 */
function forward_recipient_list($form_state) {

  // Process variables for use as tokens.
  $recipients = str_replace(array(
    "\r\n",
    "\n",
    "\r",
  ), ',', $form_state['values']['recipients']);
  $r = array();
  foreach (explode(',', $recipients) as $recipient) {
    if (trim($recipient) != '') {
      $r[trim($recipient)] = TRUE;
    }
  }
  $recipients = array_keys($r);
  $token = array(
    'sender' => $form_state['values']['name'],
    'recipients' => $recipients,
  );
  return array(
    'recipients' => $recipients,
    'token' => $token,
  );
}

/**
 * Submit callback function for forward form submit
 */
function forward_form_submit($form, &$form_state) {
  global $base_url, $user;
  $recipient_list = forward_recipient_list($form_state);
  $recipients = $recipient_list['recipients'];
  $forward_token = $recipient_list['token'];
  $dynamic_content = '';

  // Access control:
  // Possibly impersonate another user depending on dynamic block configuration settings
  $access_control = variable_get('forward_block_access_control', 'recipient');
  $switch_user = $access_control == 'recipient' || $access_control == 'anonymous';
  $impersonate_user = variable_get('forward_dynamic_block', 'none') != 'none' && $switch_user;
  if ($impersonate_user) {
    $original_user = $user;
    $old_state = drupal_save_session();
    drupal_save_session(FALSE);
    if ($access_control == 'recipient') {
      $account = user_load_by_mail(trim($form_state['values']['recipients']));

      // Fall back to anonymous user if recipient is not a valid account
      $user = isset($account->status) && $account->status == 1 ? $account : drupal_anonymous_user();
    }
    else {
      $user = drupal_anonymous_user();
    }
  }

  // Compose the body:
  // Note how the form values are accessed the same way they were accessed in the validate function.
  // If selected assemble dynamic footer block.
  switch (variable_get('forward_dynamic_block', '')) {
    case 'node':
      if (module_exists('blog')) {
        $dynamic_content_header = '<h3>' . t('Recent blog posts') . '</h3>';
        $query = db_select('node', 'n');
        $query
          ->fields('n', array(
          'nid',
          'title',
        ));
        $query
          ->condition('n.type', 'blog');
        $query
          ->condition('n.status', 1);
        $query
          ->orderBy('n.created', 'DESC');
        if (variable_get('forward_block_access_control', 'recipient') != 'none') {
          $query
            ->addTag('node_access');
        }
        $dynamic_content = forward_top5_list($query, $base_url, 'blog');
      }
      break;
    case 'user':
      if (variable_get('forward_block_access_control', 'recipient') != 'none' && user_access('access user profiles')) {
        $dynamic_content_header = '<h3>' . t("Who's new") . '</h3>';
        $query = db_select('users', 'u');
        $query
          ->fields('u', array(
          'uid',
          'name',
        ));
        $query
          ->condition('u.status', 0, '<>');
        $query
          ->orderBy('u.uid', 'DESC');
        $dynamic_content = forward_top5_list($query, $base_url, 'user');
      }
      break;
    case 'comment':
      if (module_exists('comment')) {
        $dynamic_content_header = '<h3>' . t('Recent comments') . '</h3>';
        $query = db_select('comment', 'c');
        $query
          ->fields('c', array(
          'nid',
          'cid',
          'subject',
        ));
        $query
          ->condition('c.status', 1);
        $query
          ->orderBy('c.created', 'DESC');
        if (variable_get('forward_block_access_control', 'recipient') != 'none') {
          $query
            ->addTag('node_access');
        }
        $dynamic_content = forward_top5_list($query, $base_url, 'comment');
      }
      break;
    case 'popular':
      if (module_exists('statistics')) {
        $dynamic_content_header = '<h3>' . t('Most Popular Content') . '</h3>';
        $query = db_select('node_counter', 's');
        $query
          ->join('node', 'n', 's.nid = n.nid');
        $query
          ->fields('n', array(
          'nid',
          'title',
        ));
        $query
          ->condition('s.totalcount', 0, '>');
        $query
          ->condition('n.status', 1);
        $query
          ->orderBy('s.totalcount', 'DESC');
        if (variable_get('forward_block_access_control', 'recipient') != 'none') {
          $query
            ->addTag('node_access');
        }
        $dynamic_content = forward_top5_list($query, $base_url, 'blog');
      }
      break;
  }

  // Only include header for non-empty dynamic block
  if ($dynamic_content) {
    $dynamic_content = $dynamic_content_header . $dynamic_content;
  }

  // Restore user if impersonating someone else during dynamic block build
  if ($impersonate_user) {
    $user = $original_user;
    drupal_save_session($old_state);
  }

  // Get current language
  $langcode = $GLOBALS['language_content']->language;

  // Send email of appropriate type based on module configuration
  if (!$form_state['values']['path'] || $form_state['values']['path'] == 'epostcard') {
    $emailtype = 'epostcard';
    $content = '';
    $returnurl = '';
    $node = NULL;
  }
  else {
    $emailtype = 'email';
    $returnurl = $form_state['values']['path'];
    $path_normal = drupal_get_normal_path($form_state['values']['path']);
    $path_array = explode('/', $path_normal);
    if ($path_array[0] == 'node' && !empty($path_array[1]) && is_numeric($path_array[1])) {
      $nid = $path_array[1];

      // we have a node
      $content = node_load($nid);
      if (!node_access('view', $content)) {

        // Access is denied if user does not have access to view this node
        return MENU_ACCESS_DENIED;
      }
      $node = $content;
      $node->content = array();
      if (variable_get('forward_custom_viewmode', FALSE)) {
        $view_mode = 'forward';
        field_attach_prepare_view('node', array(
          $node->nid => $node,
        ), $view_mode);
        entity_prepare_view('node', array(
          $node->nid => $node,
        ));
        $node->content += field_attach_view('node', $node, $view_mode, $langcode);
        $content->teaser = render($node->content);
      }
      if (empty($content->teaser)) {
        $view_mode = variable_get('forward_full_body', FALSE) ? 'full' : 'teaser';
        field_attach_prepare_view('node', array(
          $node->nid => $node,
        ), $view_mode);
        entity_prepare_view('node', array(
          $node->nid => $node,
        ));
        $node->content += field_attach_view('node', $node, $view_mode, $langcode);
        $content->teaser = render($node->content);
      }
    }
    else {

      // We don't have a node.
      $node = NULL;
      $_GET['q'] = $form_state['values']['path'];
      menu_set_active_item($form_state['values']['path']);

      // Adapted from index.php.
      $content = new stdClass();
      $content->body = menu_execute_active_handler(NULL, FALSE);
      $content->title = menu_get_active_title();

      // It may happen that a drupal_not_found is called in the above call
      $headers = drupal_get_http_header();
      if ($headers) {
        foreach ($headers as $header) {
          if (preg_match('/404 Not Found/', $header) == 1) {
            return;
          }
        }
      }
      switch ($content->body) {
        case MENU_NOT_FOUND:
          return MENU_NOT_FOUND;
          break;
        case MENU_ACCESS_DENIED:
          return MENU_ACCESS_DENIED;
          break;
      }
      $content->teaser = '';
      $content->body = '';
      $content->type = '';
    }
  }
  if (variable_get('forward_message', TRUE)) {
    $message = variable_get('forward_filter_html', FALSE) ? nl2br(filter_xss(token_replace($form_state['values']['message'], array(
      'node' => $node,
      'user' => $user,
      'forward' => $forward_token,
    )), explode(',', variable_get('forward_filter_tags', 'p,br,em,strong,cite,code,ul,ol,li,dl,dt,dd')))) : nl2br(check_plain(token_replace($form_state['values']['message'], array(
      'node' => $node,
      'user' => $user,
      'forward' => $forward_token,
    ))));
  }
  else {
    $message = FALSE;
  }
  global $theme_key;
  $theme_key = variable_get('theme_default', '');
  $logo = variable_get('forward_header_image', '') == '' ? theme_get_setting('logo') : variable_get('forward_header_image', '');
  $vars = array(
    'type' => $emailtype,
    'site_name' => check_plain(variable_get('site_name', 'Drupal')),
    'name' => check_plain($form_state['values']['name']),
    'email' => check_plain($form_state['values']['email']),
    'forward_message' => token_replace(t(variable_get('forward_' . $emailtype . '_message', '[forward:sender] thought you would like to see the [site:name] web site.')), array(
      'node' => $node,
      'user' => $user,
      'forward' => $forward_token,
    )),
    'message' => $message,
    'base_url' => $base_url,
    'content' => $content,
    'path' => $returnurl . $form_state['values']['path_cid'],
    'dynamic_content' => $dynamic_content,
    'forward_ad_footer' => variable_get('forward_ad_footer', ''),
    'forward_footer' => variable_get('forward_footer', ''),
    // New values for forward.tpl.php
    'site_url' => url('forward/emailref', array(
      'absolute' => TRUE,
      'query' => array(
        'path' => '<front>',
      ),
    )),
    'width' => variable_get('forward_width', 400),
    'logo' => !empty($logo) ? '<img src="' . url($logo, array(
      'absolute' => TRUE,
    )) . '" alt="" />' : '',
    'title' => $emailtype == 'email' ? l($content->title, 'forward/emailref', array(
      'absolute' => TRUE,
      'query' => array(
        'path' => $returnurl,
      ),
    )) : FALSE,
    'submitted' => $emailtype == 'email' && variable_get('node_submitted_' . $content->type) ? !empty($content->name) ? t('by %author', array(
      '%author' => $content->name,
    )) : t('by %author', array(
      '%author' => variable_get('anonymous', 'Anonymous'),
    )) : FALSE,
    'node' => $emailtype == 'email' ? $content->teaser : FALSE,
    'link' => $emailtype == 'email' ? l(t('Click here to read more on our site'), 'forward/emailref', array(
      'absolute' => TRUE,
      'query' => array(
        'path' => $returnurl . $form_state['values']['path_cid'],
      ),
    )) : FALSE,
  );
  if (variable_get('forward_theme_template', 0)) {

    // New forward.tpl.php
    $params['body'] = theme('forward', array(
      'vars' => $vars,
    ));
  }
  else {

    // Old forward_*_theme functions
    $hook = $emailtype == 'epostcard' ? 'postcard' : $emailtype;
    $params['body'] = theme('forward_' . $hook, array(
      'vars' => $vars,
    ));
  }

  // Apply pathologic so relative links are converted to external links
  $filter_format = variable_get('forward_filter_format', '');
  if ($filter_format) {

    // This filter was setup by the forward administrator for this purpose only, whose permission to run the filter was checked at that time
    // Therefore, no need to check again here
    $params['body'] = check_markup($params['body'], $filter_format, $langcode);
  }

  // Subject
  $params['subject'] = token_replace(t(variable_get('forward_' . $emailtype . '_subject', '[forward:sender] has sent you a message from [site:name]')), array(
    'node' => $node,
    'user' => $user,
    'forward' => $forward_token,
  ));
  $from = variable_get('forward_sender_address', '');
  if (empty($from)) {
    $from = variable_get('site_mail', '');
  }
  $params['from'] = trim(mime_header_encode($form_state['values']['name']) . ' <' . $from . '>');
  $params['headers']['Reply-To'] = trim(mime_header_encode($form_state['values']['name']) . ' <' . $form_state['values']['email'] . '>');
  foreach ($recipients as $to) {
    drupal_mail('forward', 'forward_page', trim($to), language_default(), $params, $params['from']);

    // Flood control
    flood_register_event('forward');
  }

  // insert record into db to record nid, type and timestamp of send
  $id = db_insert('forward_log')
    ->fields(array(
    'path' => $form_state['values']['path'],
    'type' => 'SENT',
    'timestamp' => REQUEST_TIME,
    'uid' => $user->uid,
    'hostname' => ip_address(),
  ))
    ->execute();

  // update node forward statistics
  if (!empty($nid)) {
    db_update('forward_statistics')
      ->fields(array(
      'last_forward_timestamp' => REQUEST_TIME,
    ))
      ->expression('forward_count', 'forward_count + 1')
      ->condition('nid', $nid)
      ->execute();
  }
  variable_set('forward_total', variable_get('forward_total', 0) + 1);
  variable_set('forward_recipients', variable_get('forward_recipients', 0) + count($recipients));
  drupal_set_message(token_replace(t(variable_get('forward_thankyou', 'Thank you for spreading the word about [site:name].  We appreciate your help.')), array(
    'node' => $node,
    'user' => $user,
    'forward' => $forward_token,
  )), 'status');
  if (variable_get('forward_thankyou_send', FALSE)) {
    $thankyou_params = array(
      'from' => $from,
      'subject' => token_replace(t(variable_get('forward_thankyou_subject', 'Thank you for spreading the word about [site:name]')), array(
        'node' => $node,
        'user' => $user,
        'forward' => $forward_token,
      )),
      'body' => token_replace(t(variable_get('forward_thankyou_text', "Dear [forward:sender],\n\nThank you for spreading the word about [site:name]. We appreciate your help.")), array(
        'node' => $node,
        'user' => $user,
        'forward' => $forward_token,
      )),
    );
    $mail = drupal_mail('forward', 'forward_thankyou', trim($form_state['values']['email']), language_default(), $thankyou_params, $thankyou_params['from']);
  }
  $form_state['redirect'] = $returnurl != '' ? $returnurl : variable_get('forward_epostcard_return', '');

  // CRMAPI integration
  if (module_exists('crmapi')) {
    if (!empty($user->crmapi_contact) && is_numeric($user->crmapi_contact)) {
      $contact = crmapi_contact_load('', $user->crmapi_contact);
      $contact_id = $user->crmapi_contact;
    }
    else {
      $contact['email'] = $form_state['values']['email'];
      $names = explode(' ', $form_state['values']['name']);
      $contact['first_name'] = $names[0];
      $contact['last_name'] = isset($names[2]) ? $names[2] : $names[1];
      $contact['mail_name'] = $form_state['values']['name'];
      $contact_id = crmapi_contact_save($contact);
    }
    $activity_params = array(
      'contact_id' => $contact_id,
      'activity_id' => 'OLForward',
      'activity_type' => 'F',
      'level' => '',
      'flag' => '',
      'description' => substr(url($returnurl, array(
        'absolute' => TRUE,
      )), 0, 100),
    );
    crmapi_activity_save($activity_params);
  }

  // Rules integration
  if (module_exists('rules')) {
    rules_invoke_event('node_forward', $user, $node);
  }
}

/**
 * Implements template_preprocess_module().
 */
function template_preprocess_forward(&$variables) {
  $vars = $variables['vars'];
  foreach ($vars as $key => $value) {
    $variables[$key] = $value;
  }
}

/**
* Implements hook_entity_info_alter().
*/
function forward_entity_info_alter(&$entity_info) {
  if (variable_get('forward_custom_viewmode', FALSE)) {
    $entity_info['node']['view modes']['forward'] = array(
      'label' => t('Forward'),
      'custom settings' => TRUE,
    );
  }
}

/**
 * Implements hook_mollom_form_list().
 */
function forward_mollom_form_list() {
  $forms['forward_form'] = array(
    'title' => t('Email a friend form'),
  );
  return $forms;
}

/**
 * Implements hook_mollom_form_info().
 */
function forward_mollom_form_info($form_id) {
  switch ($form_id) {
    case 'forward_form':
      $form_info = array(
        'mode' => MOLLOM_MODE_ANALYSIS,
        'bypass access' => array(
          'administer forward',
        ),
        'mail ids' => array(
          'forward_forward_page',
        ),
        'elements' => array(
          'message' => t('Personal Message'),
        ),
        'mapping' => array(
          'post_title' => 'title',
          'author_name' => 'name',
          'author_mail' => 'email',
        ),
      );
      return $form_info;
  }
}

/**
 * Implements hook_mail().
 *
 *
 * Constructs the email notification message when the site is out of date.
 *
 * @param $key
 *   Unique key to indicate what message to build, always 'forward_page'.
 * @param $message
 *   Reference to the message array being built.
 * @param $params
 *   Array of parameters to indicate what text to include in the message body.
 *
 * @see drupal_mail()
 * @see _update_cron_notify()
 * @see _update_message_text()
 */
function forward_mail($key, &$message, $params) {
  $message['subject'] .= $params['subject'];
  $message['body'][] = $params['body'];
  if ($key == 'forward_page') {
    $message['headers']['MIME-Version'] = '1.0';
    $message['headers']['Content-Type'] = 'text/html; charset=utf-8';
    $message['headers']['Reply-To'] = $params['headers']['Reply-To'];
  }
}
function forward_page_alter(&$page) {

  // Remove blocks from basic overlay
  if (variable_get('forward_colorbox_enable', 0) && isset($_GET['overlay']) && $_GET['overlay'] != 'cboxnode' && !form_get_errors()) {
    if (isset($page['#type']) && $page['#type'] == 'page' && isset($page['content']['system_main']['#form_id']) && $page['content']['system_main']['#form_id'] == 'forward_form') {
      global $theme;
      $regions = system_region_list($theme);
      foreach ($regions as $key => $region) {
        if (isset($page[$key])) {
          if ($key != 'content') {
            unset($page[$key]);
          }
        }
      }
    }
  }

  // Handle pending AJAX message
  if (isset($_SESSION['forward_message_pending'])) {
    global $user;
    $user = user_load($user->uid);
    if (arg(0) == 'node' && is_numeric(arg(1))) {
      $node = node_load(arg(1));
    }
    else {
      $node = NULL;
    }
    $forward_token = $_SESSION['forward_message_pending'];
    $message = 'Thank you for spreading the word about [site:name].  We appreciate your help.';
    drupal_set_message(token_replace(t(variable_get('forward_thankyou', $message)), array(
      'node' => $node,
      'user' => $user,
      'forward' => $forward_token,
    )), 'status');
    unset($_SESSION['forward_message_pending']);
  }
}

/**
 * Implements hook_node_view().
 */
function forward_node_view($node, $view_mode) {
  if (user_access('access forward') && variable_get('forward_display_' . $node->type, 1)) {
    $show = $view_mode == 'full' && variable_get('forward_display_nodes', 1) || $view_mode == 'teaser' && variable_get('forward_display_teasers', 0);
    if (variable_get('forward_form_type', 'link') == 'link') {
      if ($show) {
        $link = forward_link_create($node);
        $links = array();
        $links['forward_link'] = array(
          'title' => $link['title'],
          'href' => 'forward',
          'html' => $link['html'],
          'attributes' => $link['attributes'],
          'query' => $link['query'],
        );
        $node->content['links']['forward'] = array(
          '#theme' => 'links',
          '#links' => $links,
          '#attributes' => array(
            'class' => array(
              'links',
              'inline',
            ),
          ),
        );
      }
    }
    elseif ($show && !isset($node->in_preview)) {
      $output = drupal_get_form('forward_form', 'node/' . $node->nid, $node, TRUE);
      $node->content['forward'] = $output;
    }
  }
}

/**
 * Implements hook_theme().
 *
 */
function forward_theme() {
  return array(
    'forward' => array(
      'variables' => array(
        'vars' => NULL,
      ),
      'template' => 'forward',
    ),
    'forward_page' => array(
      'variables' => array(
        'vars' => NULL,
        'node' => NULL,
      ),
    ),
    'forward_email' => array(
      'variables' => array(
        'vars' => NULL,
      ),
    ),
    'forward_postcard' => array(
      'variables' => array(
        'vars' => NULL,
      ),
    ),
    'forward_link' => array(
      'variables' => array(
        'node' => NULL,
        'path' => NULL,
        'block' => FALSE,
      ),
    ),
  );
}

/**
 * Implements hook_form_alter().
 */
function forward_form_alter(&$form, $form_state, $form_id) {

  // Add the node-type settings option to activate the email this page link
  if ($form_id == 'node_type_form') {
    $form['workflow']['forward_display'] = array(
      '#type' => 'checkbox',
      '#title' => t('Show forwarding link/form'),
      '#return_value' => 1,
      '#default_value' => variable_get('forward_display_' . $form['#node_type']->type, '1'),
      '#description' => t('Displays the link/form to allow visitors to forward the page to a friend. Further configuration is available on the !settings.', array(
        '!settings' => l(t('settings page'), 'admin/config/user-interface/forward'),
      )),
    );
  }
  elseif ($form_id == 'comment_admin_settings') {
    $form['viewing_options']['forward_display_comments'] = array(
      '#type' => 'checkbox',
      '#title' => t('Show forwarding link/form'),
      '#return_value' => 1,
      '#default_value' => variable_get('forward_display_comments', FALSE),
      '#description' => t('Displays the form/link to allow visitors to forward the page to a friend. Further configuration is available on the !settings.', array(
        '!settings' => l(t('settings page'), 'admin/config/user-interface/forward'),
      )),
    );
  }
  elseif ($form_id == 'forward_form') {

    // Send overlay to AJAX form submit
    if (variable_get('forward_colorbox_enable', 0) && isset($_GET['overlay']) && $_GET['overlay'] == 'cboxnode') {
      $form['#prefix'] = '<div id="cboxNodeWrapper">';
      $form['#suffix'] = '</div>';
      $form['actions']['submit']['#id'] = 'cboxSubmit';
      $form['actions']['submit']['#ajax'] = array(
        'callback' => 'forward_js_submit',
        'wrapper' => 'cboxNodeWrapper',
        'method' => 'replace',
        'effect' => 'fade',
      );
    }
  }
}

/*
 * Javascript submit handler for colorbox node version of forward form.
 */
function forward_js_submit($form, &$form_state) {

  // If there were errors, need to re-display the form
  if (form_get_errors()) {
    return $form;
  }

  // Notify next page that a message is waiting - this is needed because Ajax can't set the message queue
  $recipient_list = forward_recipient_list($form_state);
  $_SESSION['forward_message_pending'] = $recipient_list['token'];

  // Form passed validation, so redirect to a good landing page
  $returnurl = isset($form['message']['path']['#value']) ? $form['message']['path']['#value'] : '';
  $markup = '
    <script type="text/javascript">
      (function ($) {
        $(document).ready(function() {
          $.fn.colorbox.close();
          window.location = "' . url($returnurl, array(
    'absolute' => TRUE,
  )) . '";
        });
      })(jQuery);
    </script>';

  // Return our markup.
  $confirmation = array(
    '#type' => 'markup',
    '#markup' => $markup,
  );
  return $confirmation;
}

/**
 * Callback function for the Forward Tracking Page
 */
function forward_tracking() {
  $output = array();
  $output['forward_totals'] = array(
    '#markup' => '<p><strong>' . variable_get('forward_total', 0) . '</strong> ' . t('emails sent to') . ' <strong>' . variable_get('forward_recipients', 0) . '</strong> ' . t('recipients') . '</p>',
  );

  /**
   * Most Forwarded Nodes
   */
  $output['forward_most_heading'] = array(
    '#markup' => '<h2>' . t('Most Forwarded Nodes') . '</h2>',
  );
  $rows = array();
  $header = array(
    array(
      'data' => t('Title'),
    ),
    array(
      'data' => t('Path'),
    ),
    array(
      'data' => t('Forwards'),
    ),
    array(
      'data' => t('Clickthroughs'),
    ),
  );
  $query = db_select('forward_statistics', 'f', array(
    'target' => 'slave',
  ))
    ->extend('PagerDefault')
    ->element(0);
  $query
    ->innerJoin('node', 'n', 'f.nid = n.nid');
  $query
    ->fields('f', array(
    'nid',
    'last_forward_timestamp',
    'forward_count',
    'clickthrough_count',
  ))
    ->fields('n', array(
    'title',
  ))
    ->limit(10)
    ->orderBy('f.forward_count', 'DESC');
  $result = $query
    ->execute();
  $num_rows = FALSE;
  foreach ($result as $log) {
    $num_rows = TRUE;
    $_path = drupal_get_path_alias('node/' . $log->nid);
    $title = $log->nid ? $log->title : 'Front Page';
    $rows[] = array(
      l(_forward_column_width($title), $_path),
      l($_path, $_path),
      $log->forward_count,
      $log->clickthrough_count,
    );
  }
  $output['forward_most_table'] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#empty' => t('No statistics available.'),
  );
  $output['forward_most_pager'] = array(
    '#theme' => 'pager',
    '#element' => 0,
  );

  /**
   * Most Clickthroughs
   */
  $output['forward_clickthroughs_heading'] = array(
    '#markup' => '<h2>' . t('Most Clickthroughs To Nodes') . '</h2>',
  );
  $rows = array();
  $header = array(
    array(
      'data' => t('Title'),
    ),
    array(
      'data' => t('Path'),
    ),
    array(
      'data' => t('Forwards'),
    ),
    array(
      'data' => t('Clickthroughs'),
    ),
  );
  $query = db_select('forward_statistics', 'f', array(
    'target' => 'slave',
  ))
    ->extend('PagerDefault')
    ->element(1);
  $query
    ->innerJoin('node', 'n', 'f.nid = n.nid');
  $query
    ->fields('f', array(
    'nid',
    'last_forward_timestamp',
    'forward_count',
    'clickthrough_count',
  ))
    ->fields('n', array(
    'title',
  ))
    ->limit(10)
    ->orderBy('f.clickthrough_count', 'DESC');
  $result = $query
    ->execute();
  $num_rows = FALSE;
  foreach ($result as $log) {
    $num_rows = TRUE;
    $_path = drupal_get_path_alias('node/' . $log->nid);
    $title = $log->nid ? $log->title : 'Front Page';
    $rows[] = array(
      l(_forward_column_width($title), $_path),
      l($_path, $_path),
      $log->forward_count,
      $log->clickthrough_count,
    );
  }
  $output['forward_clickthroughs_table'] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#empty' => t('No statistics available.'),
  );
  $output['forward_clickthroughs_pager'] = array(
    '#theme' => 'pager',
    '#element' => 1,
  );

  /**
   * Recently Forwarded Pages
   */
  $output['forward_recent_heading'] = array(
    '#markup' => '<h2>' . t('Recent Forward Activity') . '</h2><p>' . t('SENT = email sent, REF = email clickthrough') . '</p>',
  );
  $rows = array();
  $header = array(
    array(
      'data' => t('Time'),
      'field' => 'timestamp',
      'sort' => 'desc',
    ),
    array(
      'data' => t('Type'),
      'field' => 'type',
    ),
    array(
      'data' => t('Path'),
      'field' => 'path',
    ),
    array(
      'data' => t('User ID'),
      'field' => 'uid',
    ),
    array(
      'data' => t('Hostname'),
      'field' => 'hostname',
    ),
  );
  $query = db_select('forward_log', 'f', array(
    'target' => 'slave',
  ))
    ->extend('PagerDefault')
    ->extend('TableSort')
    ->element(2);
  $query
    ->innerJoin('users', 'u', 'f.uid = u.uid');
  $query
    ->fields('f', array(
    'timestamp',
    'type',
    'path',
    'uid',
    'hostname',
  ))
    ->fields('u', array(
    'name',
  ))
    ->limit(30)
    ->orderByHeader($header);
  $result = $query
    ->execute();
  $num_rows = FALSE;
  foreach ($result as $log) {
    $num_rows = TRUE;
    $_path = drupal_get_path_alias($log->path);
    $rows[] = array(
      array(
        'data' => format_date($log->timestamp, 'short'),
        'nowrap' => 'nowrap',
      ),
      $log->type,
      l($_path, $_path),
      l($log->name, 'user/' . $log->uid),
      $log->hostname,
    );
  }
  $output['forward_recent_table'] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
    '#empty' => t('No statistics available.'),
  );
  $output['forward_recent_pager'] = array(
    '#theme' => 'pager',
    '#element' => 2,
  );
  drupal_set_title(t('Forward Tracking'));
  return $output;
}

/**
 * Implements hook_block_info().
 */
function forward_block_info() {
  $blocks['stats']['info'] = t('Forward: Statistics');
  $blocks['stats']['cache'] = DRUPAL_NO_CACHE;
  $blocks['form']['info'] = t('Forward: Interface');
  $blocks['form']['cache'] = DRUPAL_NO_CACHE;
  return $blocks;
}

/**
 * Implements hook_block_configure().
 */
function forward_block_configure($delta) {
  switch ($delta) {
    case 'stats':
      $block_options = array(
        'allTime' => t('Most Emailed of All Time'),
        'recent' => t('Most Recently Emailed'),
      );
      $form['forward_block_type'] = array(
        '#type' => 'radios',
        '#title' => t('Block type'),
        '#default_value' => variable_get('forward_block_type', ""),
        '#options' => $block_options,
        '#description' => t('Choose the type of statistics to display'),
      );
      return $form;
    case 'form':
      $form['forward_block_form'] = array(
        '#type' => 'radios',
        '#title' => t('Interface'),
        '#default_value' => variable_get('forward_block_form', variable_get('forward_form_type', 'link')),
        '#options' => array(
          'form' => 'form',
          'link' => 'link',
        ),
        '#description' => t('Choose whether to display the full form in the block or just an email this page link.'),
      );
      return $form;
  }
}

/**
 * Implements hook_block_save().
 */
function forward_block_save($delta, $edit) {
  switch ($delta) {
    case 'stats':
      variable_set('forward_block_type', $edit['forward_block_type']);
      break;
    case 'form':
      variable_set('forward_block_form', $edit['forward_block_form']);
      break;
  }
}

/**
 * Implements hook_block_view().
 */
function forward_block_view($delta) {
  switch ($delta) {
    case 'stats':
      if (user_access('access content')) {
        $block = array();
        $query = db_select('forward_statistics', 'f');
        $query
          ->leftJoin('node', 'n', 'f.nid = n.nid');
        $query
          ->fields('f');
        $query
          ->fields('n', array(
          'nid',
          'title',
        ));
        $query
          ->range(0, 5);
        $query
          ->addTag('node_access');
        switch (variable_get('forward_block_type', 'allTime')) {
          case 'allTime':
            $query
              ->condition('f.forward_count', 0, '>');
            $query
              ->orderBy('f.forward_count', 'DESC');
            $block['subject'] = t("Most Emailed");
            $block['content'] = node_title_list($query
              ->execute());
            break;
          case 'recent':
            $query
              ->orderBy('f.last_forward_timestamp', 'DESC');
            $block['subject'] = t("Most Recently Emailed");
            $block['content'] = node_title_list($query
              ->execute());
            break;
        }
        return $block;
      }
      break;
    case 'form':
      if (user_access('access forward')) {
        if (arg(0) == 'node' && is_numeric(arg(1)) && !arg(2)) {
          $node = node_load(arg(1));
          if (!variable_get('forward_display_' . $node->type, 1)) {
            return array();
          }
        }
        else {
          $node = NULL;
        }
        if (variable_get('forward_block_form', 'link') == 'link') {
          $content = theme('forward_link', array(
            'node' => $node,
            'block' => TRUE,
          ));
        }
        else {
          if ($node) {
            $content = drupal_get_form('forward_form', 'node/' . $node->nid, $node);
          }
          else {
            $content = drupal_get_form('forward_form', $_GET['q']);
          }
        }
        return array(
          'subject' => t('Forward'),
          'content' => $content,
        );
      }
  }
}

/**
 * Theme the top 5 list of users, nodes or comments
 */
function forward_top5_list($query, $base_url, $type) {
  $items = '';
  $query
    ->range(0, 5);
  $result = $query
    ->execute();
  foreach ($result as $item) {
    if ($type == 'user') {
      $items .= '<li>' . l($item->name, 'user/' . $item->uid, array(
        'absolute' => TRUE,
      )) . '</li>';
    }
    elseif ($type == 'comment') {
      $items .= '<li>' . l($item->subject, 'node/' . $item->nid, array(
        'absolute' => TRUE,
        'fragment' => 'comment-' . $item->cid,
      )) . '</li>';
    }
    else {
      $items .= '<li>' . l($item->title, 'node/' . $item->nid, array(
        'absolute' => TRUE,
      )) . '</li>';
    }
  }
  if ($items) {
    $items = '<ul>' . $items . '</ul>';
  }
  return $items;
}
function _forward_column_width($column, $width = 35) {
  return drupal_strlen($column) > $width ? drupal_substr($column, 0, $width) . '...' : $column;
}

/**
 * Implements hook_views_api().
 */
function forward_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'forward') . '/views',
  );
}

/**
 * Modify the drupal mail system to send HTML emails for the forward module.
 */
class ForwardMailSystem implements MailSystemInterface {

  /**
   * Concatenate and wrap the e-mail body for plain-text mails.
   *
   * @param $message
   *   A message array, as described in hook_mail_alter().
   *
   * @return
   *   The formatted $message.
   */
  public function format(array $message) {
    $message['body'] = implode("\n\n", $message['body']);
    return $message;
  }

  /**
   * Send an e-mail message, using Drupal variables and default settings.
   *
   * @see http://php.net/manual/en/function.mail.php
   * @see drupal_mail()
   *
   * @param $message
   *   A message array, as described in hook_mail_alter().
   * @return
   *   TRUE if the mail was successfully accepted, otherwise FALSE.
   */
  public function mail(array $message) {
    $mimeheaders = array();
    foreach ($message['headers'] as $name => $value) {
      $mimeheaders[] = $name . ': ' . mime_header_encode($value);
    }
    $line_endings = variable_get('mail_line_endings', MAIL_LINE_ENDINGS);
    return mail($message['to'], mime_header_encode($message['subject']), preg_replace('@\\r?\\n@', $line_endings, $message['body']), join("\n", $mimeheaders));
  }

}

/**
 * Implements hook_token_info().
 */
function forward_token_info() {
  $data['types'] = array(
    'forward' => array(
      'name' => t('Forward'),
      'description' => t('Tokens related to forward module.'),
    ),
  );
  $data['tokens'] = array(
    'forward' => array(
      'recipients' => array(
        'name' => t("Email recipient(s)"),
        'description' => t("Recipient email address or email addresses for forwarded content."),
      ),
      'sender' => array(
        'name' => t("Sender's name"),
        'description' => t("Name of sender as entered in Forwarding form."),
      ),
    ),
  );
  return $data;
}

/**
 * Implements hook_tokens().
 */
function forward_tokens($type, $tokens, array $data = array(), array $options = array()) {
  $replacements = array();
  if ($type = 'node' && isset($data['forward'])) {
    foreach ($tokens as $name => $original) {
      switch ($name) {
        case 'recipients':
          $replacements[$original] = isset($data['forward']['recipients']) ? filter_xss(implode($data['forward']['recipients'], ', ')) : t('(Recipient list)');
          break;
        case 'sender':
          $replacements[$original] = isset($data['forward']['sender']) ? filter_xss($data['forward']['sender']) : t('(Your name)');
          break;
      }
    }
  }
  return $replacements;
}

Functions

Namesort descending Description
forward_block_configure Implements hook_block_configure().
forward_block_info Implements hook_block_info().
forward_block_save Implements hook_block_save().
forward_block_view Implements hook_block_view().
forward_ctools_plugin_directory Implements hook_ctools_plugin_directory().
forward_ds_fields_info Implements hook_ds_fields_info().
forward_ds_field_create Callback for Display Suite field.
forward_entity_info_alter Implements hook_entity_info_alter().
forward_form Callback function for the forward Form
forward_form_alter Implements hook_form_alter().
forward_form_submit Submit callback function for forward form submit
forward_form_validate Validation callback function for forward form submit
forward_js_submit
forward_link_create Generate a Forward link for a node or page
forward_mail Implements hook_mail().
forward_menu Implements hook_menu().
forward_mollom_form_info Implements hook_mollom_form_info().
forward_mollom_form_list Implements hook_mollom_form_list().
forward_node_delete Implements hook_node_delete().
forward_node_insert Implements hook_node_insert().
forward_node_view Implements hook_node_view().
forward_page Callback function for the forward Page
forward_page_alter
forward_permission Implements hook_permission().
forward_recipient_list
forward_theme Implements hook_theme().
forward_tokens Implements hook_tokens().
forward_token_info Implements hook_token_info().
forward_top5_list Theme the top 5 list of users, nodes or comments
forward_tracker Callback function for the Email Tracker
forward_tracking Callback function for the Forward Tracking Page
forward_views_api Implements hook_views_api().
template_preprocess_forward Implements template_preprocess_module().
theme_forward_link Theme function for Forward link
_forward_column_width

Classes

Namesort descending Description
ForwardMailSystem Modify the drupal mail system to send HTML emails for the forward module.