You are here

shoutbox.module in Shoutbox 6

shoutbox module displays a block for users to create short messages for thw whole site. Uses AHAH to update the database and display content.

File

shoutbox.module
View source
<?php

/**
 * @file
 * shoutbox module displays a block for users to create short
 * messages for thw whole site. Uses AHAH to update the
 * database and display content.
 *
 */

/**
 * Describe the shoutbox module.
 *
 * @param $section
 *   Which help screen is requested.
 * @return
 *   HTML fragment for help text.
 */
function shoutbox_help($path, $arg) {
  switch ($path) {
    case 'admin/build/modules#description':
      return t("This module enables you to display a shoutbox.");
  }
}

/**
 * Implementation of hook_menu().
 */
function shoutbox_menu() {
  $items = array();
  $items['shoutbox'] = array(
    'title' => 'All Shouts',
    'page callback' => 'shoutbox_page_view',
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['shoutbox/js/view'] = array(
    'title' => 'View Shouts',
    'page callback' => 'shoutbox_js_view',
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['shoutbox/%shoutbox/edit'] = array(
    'title' => 'Edit Shout',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'shoutbox_edit_form',
      1,
    ),
    'access callback' => '_shoutbox_user_access',
    'access arguments' => array(
      'edit own shouts',
      1,
    ),
    'type' => MENU_CALLBACK,
  );
  $items['shoutbox/%shoutbox/delete'] = array(
    'title' => 'Delete Shout',
    'page callback' => 'theme',
    'page arguments' => array(
      'shoutbox_delete_form',
      1,
    ),
    'access callback' => '_shoutbox_user_access',
    'access arguments' => array(
      'delete own shouts',
      1,
    ),
    'type' => MENU_CALLBACK,
  );
  $items['shoutbox/%shoutbox/publish'] = array(
    'title' => 'Publish Shout',
    'page callback' => 'theme',
    'page arguments' => array(
      'shoutbox_publish_form',
      1,
    ),
    'access callback' => '_shoutbox_user_access',
    'access arguments' => array(
      'moderate shoutbox',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['shoutbox/%shoutbox/unpublish'] = array(
    'title' => 'Unpublish Shout',
    'page callback' => 'theme',
    'page arguments' => array(
      'shoutbox_unpublish_form',
      1,
    ),
    'access callback' => '_shoutbox_user_access',
    'access arguments' => array(
      'moderate shoutbox',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/settings/shoutbox'] = array(
    'title' => 'Shoutbox',
    'description' => 'Settings for displaying and deleting shouts',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'shoutbox_admin_settings',
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}

/**
 * Implementation of hook_load().
 *
 */
function shoutbox_load($shout_id) {
  $shout = NULL;
  if (is_numeric($shout_id)) {
    $shout = db_fetch_object(db_query('SELECT * FROM {shoutbox} WHERE shout_id = ' . db_placeholders($shout_id), $shout_id));
    if (!$shout) {
      $shout = FALSE;
    }
  }
  else {
    $shout = drupal_not_found();
  }
  return $shout;
}

/**
 *  Make the shout box block available. (Standard Drupal hook).
 *
 * @param $op
 *   "list" to request list of blocks this module exposes;
 *   any other value to display the stock quotes block.
 * @param $delta
 *   integer block selector (only recognizes 0 = stock quotes).
 * @return
 *   (if $op == "list") array containing list of blocks.
 *   (otherwise) HTML fragment for THE block.
 */
function shoutbox_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'list':
      $blocks[0]["info"] = t("Shoutbox");
      return $blocks;
      break;
    case 'view':
      $block = array();
      drupal_add_css(drupal_get_path('module', 'shoutbox') . '/shoutbox.css');
      switch ($delta) {
        case 0:
          if (user_access("access content")) {

            // BUGBUG - why are we looking at $_GET
            if (!stristr($_GET['q'], 'shoutbox')) {

              // Bind submission to submit.
              drupal_add_js('misc/jquery.form.js');
              drupal_add_js(drupal_get_path('module', 'shoutbox') . '/shoutbox-form.js', 'module');
              $block["subject"] = t("Shout Box");
              $block["content"] = _shoutbox_block_view();
            }
          }
      }
      return $block;
      break;
    default:
      break;
  }
  return;
}

/**
 * Implementation of hook_cron().
 */
function shoutbox_cron() {
  $expiration = variable_get('shoutbox_expire', 0);
  if ($expiration > 0) {
    db_query('DELETE FROM {shoutbox} WHERE created < %d', time() - 60 * 60 * 24 * $expiration);
  }
}

/**
 * Implementation of hook_perm().
 */
function shoutbox_perm() {
  return array(
    'post shouts',
    'administer shoutbox',
    'moderate shoutbox',
    'post shouts without approval',
    'delete own shouts',
    'edit own shouts',
  );
}

/**
 * Implementation of hook_user().
 */
function shoutbox_user($op, &$edit, &$account, $category = NULL) {
  if ($op == "logout") {
    setcookie("shoutinfo", FALSE, time(), '/');
  }
}

/**
 * Implementation of hook_simpletest().
 */
function shoutbox_simpletest() {
  $dir = drupal_get_path('module', 'shoutbox') . '/tests';
  $tests = file_scan_directory($dir, '\\.test$');
  return array_keys($tests);
}

// CALLBACKS.

/**
 * Javascript callback.
 * Prints out shouts only.
 */
function shoutbox_js_view() {
  $show_amount = variable_get('shoutbox_showamount', '20');
  $shoutbox_posts_data = _shoutbox_display_posts($show_amount, FALSE);
  $output = $shoutbox_posts_data['output'];
  print $output;
}

/**
 * Show paged view of full list of shouts.
 */
function shoutbox_page_view() {
  drupal_add_css(drupal_get_path('module', 'shoutbox') . '/shoutbox.css');

  // Output the existing shoutbox posts.
  $shoutbox_posts_data = _shoutbox_display_posts(20, TRUE, TRUE);
  $output .= theme('table', array(), $shoutbox_posts_data['rows']);
  $output .= theme('pager', NULL, 3, 0);
  return $output;
}

// THEMES.

/**
 * Implementation of hook_theme().
 */
function shoutbox_theme() {
  return array(
    'shoutbox_links' => array(),
    'shoutbox_post_forbidden' => array(),
    'shoutbox_post' => array(
      'arguments' => array(
        'shout' => NULL,
        'links' => array(),
      ),
    ),
    'shoutbox_page' => array(
      'arguments' => array(
        'content' => NULL,
        'title' => 'Shoutbox',
      ),
    ),
    'shoutbox_delete_form' => array(
      'arguments' => array(
        'shout' => NULL,
      ),
      'file' => 'shoutbox.pages.inc',
    ),
    'shoutbox_publish_form' => array(
      'arguments' => array(
        'shout' => NULL,
      ),
      'file' => 'shoutbox.pages.inc',
    ),
    'shoutbox_unpublish_form' => array(
      'arguments' => array(
        'shout' => NULL,
      ),
      'file' => 'shoutbox.pages.inc',
    ),
  );
}

/**
 * Theme function of shoutbox actions. Actions are edit, delete, promote
 * and demote. NOTE: Function does not return html but rather an array
 * with the actions as keys. See code.
 */
function theme_shoutbox_links() {
  $links['edit']['action'] = 'edit';
  $links['edit']['title'] = 'Edit';
  $links['edit']['attributes'] = array(
    "class" => "edit-shout",
  );
  $links['delete']['action'] = 'delete';
  $links['delete']['title'] = 'Delete';
  $links['delete']['attributes'] = array(
    "class" => "delete-shout",
  );
  $links['publish']['action'] = 'publish';
  $links['publish']['title'] = 'Publish';
  $links['publish']['attributes'] = array(
    "class" => "publish-shout",
  );
  $links['unpublish']['action'] = 'unpublish';
  $links['unpublish']['title'] = 'Unpublish';
  $links['unpublish']['attributes'] = array(
    "class" => "unpublish-shout",
  );
  return $links;
}

/**
 * Theme function for shoutbox posts.
 *
 * @param shout
 *   The shout to be themed.
 * @param links
 *   Links of possible actions that can be performed on this shout
 *   by the current user.
 * @param $alter_row_color
 *   Whether or not to alternate the row color for posts.  Should be set to
 *   FALSE for the page view.
 */
function theme_shoutbox_post($shout, $links = array(), $alter_row_color = TRUE) {

  // Get the registered username of the person who posted the shout.
  if ($shout->uid > 0) {
    $user = user_load(array(
      "uid" => $shout->uid,
    ));
    $shout->username = $user->name;
  }
  else {
    $shout->username = 'an anonymous user';
  }

  // BUGBUG strstr returns from http:// till end
  // we should use that instead of full url.
  if (strstr($shout->url, "http://")) {
    $shout->url = '<a href="' . $shout->url . '" target="_blank">' . $shout->nick . '</a>';
  }
  else {
    $shout->url = $shout->nick;
  }
  if ($links) {
    foreach ($links as $link) {
      $linkattributes = $link['attributes'];
      $link_html = $link['title'];
      $link_url = 'shoutbox/' . $shout->shout_id . '/' . $link['action'];
      $action_links = l($link_html, $link_url, array(
        'html' => TRUE,
        'attributes' => $linkattributes,
      )) . $action_links;
    }
  }
  $title = 'Posted ' . format_date($shout->created, 'custom', 'm/d/y') . ' at ' . format_date($shout->created, 'custom', 'h:ia') . ' by ' . $shout->username;
  $shout_classes = "shoutbox-msg ";
  if ($alter_row_color) {
    $shout_classes .= $shout->color ? "shoutbox-odd " : "shoutbox-even ";
  }
  if ($shout->moderate == 1) {
    $shout_classes .= "shoutbox-unpublished ";
    $shout->shout .= t("(This shout is waiting for approval by a moderator.)");
  }
  return "<div class=\" {$shout_classes} \" title=\"{$title}\"><span class=\"actions\">{$action_links}</span> <span class=\"shout\"><b>{$shout->url}</b>: {$shout->shout}</span></div>\n";
}

/**
 * Theme function for displaying the shoutbox page.
 *
 * @param $content
 *   The page content.
 * @param $title
 *   The page title, defaults to 'Shoutbox'.
 * @return
 *   String containing HTML formatted page.
 */
function theme_shoutbox_page($content, $title = 'Shoutbox') {
  $output .= $content;
  $output = "<div id=\"shoutbox-body\">\n" . $output . "</div>\n";
  return $output;
}

/**
 * Theme function for displaying the access denied message.
 *
 * @return
 *   String containing HTML formatted access denied message.
 */
function theme_shoutbox_post_forbidden() {
  global $user;
  if ($user->uid) {
    return '<div class="shoutbox-msg">' . t("Your account does not have the permissions to post shouts") . "</div>\n";
  }
  else {
    return '<div class="shoutbox-msg">' . t('<a href="!login" target="_top">Login</a> or <a href="!register" target="_top">register</a> to post shouts', array(
      '!login' => url('user/login'),
      '!register' => url('user/register'),
    )) . "</div>\n";
  }
}

// FORMS.

/**
 * Form for admin/settings/shoutox page.
 */
function shoutbox_admin_settings() {
  $form['display_settings'] = array(
    '#type' => 'fieldset',
    '#title' => t('Display Settings'),
    '#collapsible' => true,
  );
  $form['display_settings']['shoutbox_showamount'] = array(
    '#type' => 'textfield',
    '#title' => t('Number of posts to show'),
    '#default_value' => variable_get('shoutbox_showamount', 20),
    '#size' => 4,
    '#maxlength' => 4,
    '#description' => t("Set the number of shoutbox posts to show."),
  );
  $form['display_settings']['shoutbox_ascending'] = array(
    '#type' => 'checkbox',
    '#title' => t('Post newest shouts on top'),
    '#default_value' => variable_get('shoutbox_ascending', 0),
    '#description' => t('When checked, new shouts will appear on the top instead of the bottom.'),
  );
  $form['display_settings']['shoutbox_defaultname'] = array(
    '#type' => 'checkbox',
    '#title' => t('Default the name field to the logged in user name'),
    '#default_value' => variable_get('shoutbox_defaultname', 1),
    '#description' => t('When checked, "Your name/nick" will be replaced by the logged in user name'),
  );
  $form['display_settings']['shoutbox_shownamefield'] = array(
    '#type' => 'checkbox',
    '#title' => t('Show the name field for logged in users'),
    '#default_value' => variable_get('shoutbox_shownamefield', 1),
    '#description' => t('Uncheck to hide the name field for logged in users. Name will then be the user name, so previous option will be useless.'),
  );
  $form['display_settings']['shoutbox_showurlfield'] = array(
    '#type' => 'checkbox',
    '#title' => t('Show the url field'),
    '#default_value' => variable_get('shoutbox_showurlfield', 1),
    '#description' => t('Check to allow users to enter an url.'),
  );
  $form['shoutbox_filter_format'] = _shoutbox_filter_form();
  $form['time_settings'] = array(
    '#type' => 'fieldset',
    '#title' => t('Time Settings'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );
  $form['time_settings']['shoutbox_refresh'] = array(
    '#type' => 'textfield',
    '#title' => t('Auto refresh (in seconds)'),
    '#default_value' => variable_get('shoutbox_refresh', 0),
    '#size' => 4,
    '#maxlength' => 4,
    '#description' => t("Shoutbox can be set to automatically refresh every x number of seconds.  Set to 0 to turn off the auto refresh (default)."),
  );
  $form['time_settings']['shoutbox_anonymous_timeout'] = array(
    '#type' => 'textfield',
    '#title' => t('Number of minutes for which anonymous users may edit or delete their own posts'),
    '#default_value' => variable_get('shoutbox_anonymous_timeout', 20),
    '#size' => 4,
    '#maxlength' => 4,
    '#description' => t("Anonymous users can edit or delete their post within this amount of time from it being posted, as long as they have the same IP address as when they posted it.  If you don't want shout editing and/or deleting, remove these permissions from Drupal's anonymous users role."),
  );
  $form['time_settings']['shoutbox_registered_timeout'] = array(
    '#type' => 'textfield',
    '#title' => t('Number of minutes for which registered users may edit or delete their own posts'),
    '#default_value' => variable_get('shoutbox_registered_timeout', 1440),
    '#size' => 4,
    '#maxlength' => 4,
    '#description' => t("Registered users can edit or delete their post within this amount of time from it being posted.  If you don't want editing and/or deleting, remove these permissions from Drupal's registered users role."),
  );
  $form['time_settings']['shoutbox_expire'] = array(
    '#type' => 'textfield',
    '#title' => t('Number of days after which shouts will be purged from the database'),
    '#default_value' => variable_get('shoutbox_expire', 0),
    '#size' => 4,
    '#maxlength' => 4,
    '#description' => t("Shouts will be permanently deleted after the number of days specified.  Shouts will never expire when this is set to zero."),
  );
  return system_settings_form($form);
}

/**
 * Generates form for adding shouts.
 */
function shoutbox_add_form() {
  global $user;
  if (isset($_COOKIE['shoutinfo'])) {
    $info = explode("|", $_COOKIE['shoutinfo']);
    $last_nick = $info[0];
    $last_url = $info[1];
  }
  if (variable_get('shoutbox_defaultname', 1) && $user->uid) {
    $default_nick = $user->name;
  }
  else {
    $default_nick = t('Your Name/Nick');
  }
  $default_msg = t('Enter Message');
  $default_url = t('Your Website URL');
  $form = '';
  if (!variable_get('shoutbox_shownamefield', 1) && $user->uid) {
    $form['nick'] = array(
      '#type' => 'hidden',
      '#value' => $user->name,
    );
  }
  else {
    $form['nick'] = array(
      '#type' => 'textfield',
      '#default_value' => $last_nick ? $last_nick : $default_nick,
      '#size' => 15,
      '#maxlength' => 30,
    );
  }
  $form['message'] = array(
    '#type' => 'textfield',
    '#default_value' => $default_msg,
    '#size' => 15,
  );
  if (variable_get('shoutbox_showurlfield', 1)) {
    $form['url'] = array(
      '#type' => 'textfield',
      '#default_value' => $last_url ? $last_url : $default_url,
      '#size' => 15,
      '#maxlength' => 255,
    );
  }
  $form['#attributes'] = array(
    'name' => 'shoutbox_add',
  );
  $form['#prefix'] = '<div class="shoutbox-add-form">';
  $form['#suffix'] = '</div>';
  $form['ajax'] = array(
    '#type' => 'hidden',
    '#default_value' => 0,
  );
  $form['nextcolor'] = array(
    '#type' => 'hidden',
    '#default_value' => $color,
  );
  $form[] = array(
    '#type' => 'submit',
    '#value' => t('Shout'),
  );
  return $form;
}

/**
 * Form for editing shouts.
 *
 * @param shout_id
 *   The shout id of the shout being edited.
 */
function shoutbox_edit_form(&$form_state, $shout) {
  global $user;
  if (_shoutbox_user_access('administer shoutbox')) {
    $form[] = array(
      '#type' => 'item',
      '#title' => t('Created'),
      '#value' => date('m/d/y h:i:sa', $shout->created),
    );
    $form[] = array(
      '#type' => 'item',
      '#title' => t('Changed'),
      '#value' => date('m/d/y h:i:sa', $shout->changed),
    );
    $form['moderate'] = array(
      '#type' => 'radios',
      '#title' => t('Moderation Status'),
      '#default_value' => $shout->moderate,
      '#options' => array(
        'not published',
        'published',
      ),
    );
    $users[0] = variable_get('anonymous', 'Anonymous');
    $result = db_query("SELECT uid, name FROM {users} WHERE name <> '' ORDER BY name");
    while ($usr = db_fetch_object($result)) {
      $users[$usr->uid] = $usr->name;
    }
    $form['uid'] = array(
      '#type' => 'select',
      '#title' => t('Author'),
      '#default_value' => $shout->uid,
      '#options' => $users,
    );
  }
  if (_shoutbox_user_access('edit own shouts', $shout)) {
    if (!variable_get('shoutbox_shownamefield', 1) && $user->uid) {
      $form['nick'] = array(
        '#type' => 'hidden',
        '#value' => $shout->nick,
      );
    }
    else {
      $form['nick'] = array(
        '#type' => 'textfield',
        '#title' => t('Name/Nick'),
        '#default_value' => $shout->nick,
        '#size' => 16,
        '#maxlength' => 55,
      );
    }
    $form['shout'] = array(
      '#type' => 'textarea',
      '#title' => t('Shout'),
      '#default_value' => $shout->shout,
      '#cols' => 13,
      '#rows' => 7,
    );
    if (variable_get('shoutbox_showurlfield', 1)) {
      $form['url'] = array(
        '#type' => 'textfield',
        '#title' => t('URL'),
        '#default_value' => $shout->url,
        '#size' => 16,
        '#maxlength' => 55,
      );
    }
    $form['shout_id'] = array(
      '#type' => 'hidden',
      '#value' => $shout->shout_id,
    );
  }
  $form = confirm_form($form, t(''), t(''), t(''), t('Update'), t('Cancel'));
  return $form;
}

/**
 * Displays a "Are you sure message ?" with a Yes and Cancel
 * option.
 *
 * @param shout_id
 *   The shout id of the shout being edited.
 */
function shoutbox_delete_form(&$form_state, $shout) {
  $form['shout_id'] = array(
    '#type' => 'value',
    '#value' => $shout->shout_id,
  );
  $form = confirm_form($form, t('Are you sure you want to delete this shout?'), '');
  return $form;
}

/**
 * Displays a "Are you sure message ?" with a Yes and Cancel
 * option.
 *
 * @param shout_id
 *   The shout id of the shout being published.
 */
function shoutbox_publish_form(&$form_state, $shout) {
  $form['shout_id'] = array(
    '#type' => 'value',
    '#value' => $shout->shout_id,
  );
  $form = confirm_form($form, t('Are you sure you want to publish this shout?'), '', t(''));
  return $form;
}

/**
 * Displays a "Are you sure message ?" with a Yes and Cancel
 * option.
 *
 * @param shout_id
 *   The shout id of the shout being unpublished.
 */
function shoutbox_unpublish_form(&$form_state, $shout) {
  $form['shout_id'] = array(
    '#type' => 'value',
    '#value' => $shout->shout_id,
  );
  $form = confirm_form($form, t('Are you sure you want to unpublish this shout?'), '', t(''));
  return $form;
}

// FORM SUBMITS.

/**
 * Handles submission of a shout.
 * Handles both ajax submission and regular form submission.
 */
function shoutbox_add_form_submit($form, $form_state) {
  global $user;

  // Save the user's nick and url in a cookie for next time (expires in 30 days)
  setcookie("shoutinfo", "{$form_state['values']['nick']}|{$form_state['values']['url']}", time() + 60 * 60 * 24 * 30, '/');
  $moderate = 0;

  // Check user's permission and set shout visibility status accordingly.
  if (!_shoutbox_user_access('post shouts without approval')) {
    $moderate = 1;
  }
  $created = time();

  // Add shout to the database.
  db_query("INSERT INTO {shoutbox} (uid, nick, shout, url, moderate, created, changed, sid) VALUES (%d, '%s', '%s', '%s', %d, %d, %d, '%s')", $user->uid, $form_state['values']['nick'], $form_state['values']['message'], $form_state['values']['url'], $moderate, $created, $created, session_id());

  // If form was not submitted via javascript
  // set a display message and redirect the user
  if ($form_state['values']['ajax'] == '0') {
    if ($moderate == 1) {
      drupal_set_message(t('Your shout has been submitted for approval by a moderator. Others will not see this shout until it is approved.'));
    }
    else {
      drupal_set_message(t('Your shout has been submitted.'));
    }
    drupal_goto("");
  }
  else {

    // Pull shout out of db and display.
    // We are pulling it out because thats the only way to get th shout_id
    // which is need for edit, etc.
    $shout = db_fetch_object(db_query("SELECT * FROM {shoutbox} WHERE nick = '%s' AND shout = '%s' AND created = %d AND sid = '%s'", $form_state['values']['nick'], $form_state['values']['message'], $created, session_id()));

    // Add shout color.
    $shout->color = $form_state['values']['nextcolor'];
    _shoutbox_sanitize_shout($shout);

    // Add edit/delete links depending on user's permissions.
    $shoutlinks = _shoutbox_get_links($shout);
    $ajax_output = theme('shoutbox_post', $shout, $shoutlinks);
    print $ajax_output;

    // Exit required to stop drupal from redirecting page.
    exit;
  }
}

/**
 * Handle the edit form submission.
 *
 * @param $form_id
 *   The form ID of the form.
 * @param $form_values
 *   Form values.
 */
function shoutbox_edit_form_submit($form, $form_state) {
  if (is_numeric($form_state['values']['shout_id'])) {

    // Get existing shout object.
    $result = db_query("SELECT * FROM {shoutbox} WHERE shout_id = %d", $form_state['values']['shout_id']);
    $existing_shout = db_fetch_object($result);

    // If the user is a shoutbox admin they can edit any shout.
    if (_shoutbox_user_access('administer shoutbox')) {
      db_query("UPDATE {shoutbox} SET uid=%d, nick='%s', shout='%s', url='%s', moderate=%d, changed=%d WHERE shout_id=%d", $form_state['values']['uid'], $form_state['values']['nick'], $form_state['values']['shout'], $form_state['values']['url'], $form_state['values']['moderate'], time(), $form_state['values']['shout_id']);
      drupal_set_message(t('The shout has been saved.'));
    }
    else {
      if (_shoutbox_user_access('edit own shouts', $existing_shout)) {
        db_query("UPDATE {shoutbox} SET nick='%s', shout='%s', url='%s', changed=%d WHERE shout_id=%d", $form_state['values']['nick'], $form_state['values']['shout'], $form_state['values']['url'], time(), $form_state['values']['shout_id']);
        drupal_set_message(t('Your shout has been saved.'));
      }
      else {
        shoutbox_set_message(t('You do not have permission to edit this shout.'));
      }
    }
  }
  else {
    return drupal_not_found();
  }
  drupal_goto('');
}

/**
 * Handle the delete form submission.
 */
function shoutbox_delete_form_submit($form, &$form_state) {
  $form_state['redirect'] = '';
  if ($form_state['clicked_button']['#value'] == t('Confirm')) {
    if (is_numeric($form_state['values']['shout_id'])) {
      $result = db_query("SELECT * FROM {shoutbox} WHERE shout_id = %d", $form_state['values']['shout_id']);
      if ($shout = db_fetch_object($result)) {
        if (_shoutbox_user_access('delete own shouts', $shout)) {
          db_query("DELETE FROM {shoutbox} WHERE shout_id =%d", $form_state['values']['shout_id']);
          drupal_set_message(t('Your shout was deleted.'));
        }
        else {
          drupal_set_message(t('You do not have permission to delete this post.'));
        }
      }
      else {
        return drupal_not_found();
      }
    }
  }
}

/**
 * Handle the publish form submission.
 */
function shoutbox_publish_form_submit($form, &$form_state) {
  if ($form_state['clicked_button']['#value'] == t('Confirm')) {
    $form_state['redirect'] = '';
    return _shoutbox_moderate_shout($form_state['values']['shout_id'], 0);
  }
}

/**
 * Handle the unpublish form submission.
 */
function shoutbox_unpublish_form_submit($form, &$form_state) {
  if ($form_state['clicked_button']['#value'] == t('Confirm')) {
    $form_state['redirect'] = '';
    return _shoutbox_moderate_shout($form_state['values']['shout_id'], 1);
  }
}

// FORM VALIDATE.

/**
 * Makes sure uses don't submit default values.
 *
 * @param $form_id
 *   The form ID of the form.
 * @param $form_values
 *   Form values.
 */
function shoutbox_add_form_validate($form, $form_state) {
  if ($form_state['values']['nick'] == t('Your Name/Nick') || $form_state['values']['message'] == t('Enter Message')) {
    form_set_error('', t('Default values are not acceptable'));
  }
  if ($form_state['values']['nick'] == '' || $form_state['values']['message'] == '') {
    form_set_error('', t('You must enter a nick and a message.'));
  }

  // url is optional
  if ($form_state['values']['url'] == t('Your Website URL')) {
    $form_state['values']['url'] = '';
  }
}

// INTERNAL FUNCTIONS.

/**
 * Returns the themed HTML to be displayed in the block.
 *
 * @return
 *   Themed HTML content.
 */
function _shoutbox_block_view() {

  // Output the existing shoutbox posts.
  $show_amount = variable_get('shoutbox_showamount', '20');
  $shoutbox_ascending = variable_get('shoutbox_ascending', FALSE);
  $shoutbox_posts_data = _shoutbox_display_posts($show_amount);
  $output = $shoutbox_posts_data['output'];

  // Output the shoutbox form.
  if (_shoutbox_user_access('post shouts') || _shoutbox_user_access('post shouts without approval')) {
    $output .= drupal_get_form('shoutbox_add_form');
  }
  else {
    $output .= theme('shoutbox_post_forbidden');
  }
  $default_nick = t('Your Name/Nick');
  $default_msg = t('Enter Message');
  $default_url = t('Your Website URL');

  // Variable needed by javascript code.
  $js_settings = array(
    'showAmount' => $show_amount,
    // Convert to milliseconds.
    'refreshDelay' => 1000 * variable_get('shoutbox_refresh', 0),
    'ascending' => $shoutbox_ascending,
    'shownAmount' => $shoutbox_posts_data['count'],
    'defaultNick' => $default_nick,
    'defaultMsg' => $default_msg,
    'defaultUrl' => $default_url,
    'refreshPath' => url('shoutbox/js/view'),
  );
  drupal_add_js(array(
    'shoutbox' => $js_settings,
  ), 'setting');
  $output .= l(t('All Shouts'), 'shoutbox');
  return theme('shoutbox_page', $output, $title);
}

/**
 * Output existing shoutbox posts as html.
 * Used by shoutbox_get_view.
 *
 * @param $show_amount
 *   The number of posts to show.
 * @param $wrap
 *   Whether or not to wrap posts in <div id="shoutbox-posts">
 * @param $pager
 *   Whether or not to use pager_query() instead of db_query_range(), defaults
 *   to FALSE.
 * @return
 *   HTML for show_amount number of posts.
 */
function _shoutbox_display_posts($show_amount, $wrap = TRUE, $pager = FALSE) {
  $color = 0;
  $count = 0;
  $output = '';

  // TODO: Output of this function should be single array
  $rows = array();

  // Figure out if we should display it in ascending or descending order.
  $ascending = variable_get('shoutbox_ascending', FALSE);

  // Get the shouts from the database.
  if (!$pager) {
    $result = db_query_range("SELECT * FROM {shoutbox} ORDER BY created DESC", 0, $show_amount);
  }
  else {
    $result = pager_query("SELECT * FROM {shoutbox} ORDER BY created DESC", $show_amount);
  }
  while ($shout = db_fetch_object($result)) {
    if ($shout->moderate == 0 || _shoutbox_user_access('moderate shoutbox') || _shoutbox_is_user_owned($shout)) {
      _shoutbox_sanitize_shout($shout);

      // Add edit/delete links depending on user's permissions.
      $shoutlinks = _shoutbox_get_links($shout);

      // Alternate colors for each post (row of the shoutbox).
      if ($color == 0) {
        $color = 1;
      }
      else {
        $color = 0;
      }
      $shout->color = $color;

      // Theme the shoutbox post.
      if ($ascending) {
        $output .= theme('shoutbox_post', $shout, $shoutlinks);
      }
      else {
        $output = theme('shoutbox_post', $shout, $shoutlinks) . $output;
      }
      $rows[] = array(
        theme('shoutbox_post', $shout, $shoutlinks, FALSE),
      );
      ++$count;
    }
  }
  if (!$ascending) {
    $rows = array_reverse($rows);
  }
  if (!$count) {
    $output .= '<div class="shoutbox-even" title="no shouts">' . t("There are no shouts to view.") . "</div>\n";
  }

  // Don't wrap for ahah refreshes
  if ($wrap) {

    // Wrap shout box messages.
    $output = "<div id=\"shoutbox-posts\">\n" . $output . "</div>\n";
  }
  $output_data['count'] = $count;
  $output_data['output'] = $output;
  $output_data['rows'] = $rows;
  return $output_data;
}

/**
 * Returns an array containing the possible actions for the current user based
 * on permissions and shout. The actions are edit, delete, moderate.
 *
 * @param shout
 *   The shout for which we are testing permissions.
 * @return
 *   Array of themed actions.
 */
function _shoutbox_get_links($shout) {
  global $user;
  $links = theme('shoutbox_links');

  // Get array of links.
  if (_shoutbox_user_access('edit own shouts', $shout)) {
    $shoutlinks[] = $links['edit'];
  }
  if (_shoutbox_user_access('delete own shouts', $shout)) {
    $shoutlinks[] = $links['delete'];
  }
  if (_shoutbox_user_access('moderate shoutbox', $shout)) {
    if ($shout->moderate == 0) {
      $shoutlinks[] = $links['unpublish'];
    }
    else {
      $shoutlinks[] = $links['publish'];
    }
  }
  return $shoutlinks;
}

/**
 * This function is necessary because even if a user has permission
 * (according to the user_access function), they still should not have
 * some permissions, such as moderating their own posts, etc.
 *
 * @param $permission
 *   The user's permissions.
 * @param $shout
 *   The shout post object.
 * @return
 *   Returns 1 if user should have accces, 0 otherwise.
 */
function _shoutbox_user_access($permission, $shout = NULL) {
  global $user;
  if (user_access('administer shoutbox')) {
    return TRUE;
  }
  $user_timeout = FALSE;
  $user_owned = FALSE;
  $access_granted = user_access($permission);

  // If user_access says no, it's definitely no.
  if ($access_granted && ($permission == 'edit own shouts' || $permission == 'delete own shouts')) {
    if (_shoutbox_is_user_owned($shout)) {

      // A registered user's own post.
      if ($shout->uid > 0 && $shout->created < time() - 60 * variable_get('shoutbox_registered_timeout', 1440)) {
        $user_timeout = TRUE;
      }
      else {
        if ($shout->uid == 0 && $shout->created < time() - 60 * variable_get('shoutbox_anonymous_timeout', 20)) {
          $user_timeout = TRUE;
        }
      }
      $user_owned = TRUE;
    }

    // If not user owned the post or editing priviledges have timed out ...
    $access_granted = $user_owned && !$user_timeout;
  }
  return $access_granted;
}

/**
 * This function cleans the shout object before it is used.
 *
 * @param &$shout
 *   The shout post object.
 */
function _shoutbox_sanitize_shout(&$shout) {

  // All filtering (including urls, email addresses, censored words, and
  // emoticons) is handled by the drupal filter system.
  $shout->nick = check_plain($shout->nick);
  $format = variable_get('shoutbox_filter_format', 'PLAIN');
  if ($format == 'PLAIN') {
    $shout->shout = check_plain($shout->shout);
  }
  else {

    // ADD HUGE WARNING ABOUT DANGERS OF NOT FILTERING HTML
    $shout->shout = check_markup($shout->shout, $format, FALSE);
  }
  $shout->url = check_url($shout->url);
  $shout->color = check_plain($shout->color);
}
function _shoutbox_filter_form() {
  $form = filter_form(variable_get('shoutbox_filter_format', 'FILTER_FORMAT_DEFAULT'), NULL, array(
    'shoutbox_filter_format',
  ));
  $formats = filter_formats();
  if (count($formats) > 1) {
    $form['#title'] = t('Shoutbox Input Format');
  }
  return $form;
}

/**
 * Update the moderate bit in the database.
 *
 * @param $shout_id
 *   The shout id of the shout being moderated.
 *
 * @param $moderate
 *   The vale to set the moderate bit to. (0 or 1)
 *
 * @return
 *    N/A
 */
function _shoutbox_moderate_shout($shout_id, $moderate) {
  if (is_numeric($shout_id) && ($moderate == 0 || $moderate == 1)) {
    if (_shoutbox_user_access('moderate shoutbox')) {
      db_query("UPDATE {shoutbox} set moderate='%d' WHERE shout_id =%d", $moderate, $shout_id);
      if ($moderate == 0) {
        drupal_set_message(t('The shout was published.'));
      }
      else {
        drupal_set_message(t('The shout was unpublished.'));
      }
    }
    else {
      drupal_set_message(t('You do not have permission to moderate this shout.'));
    }
  }
  else {
    return drupal_not_found();
  }
}

/**
 * Determine if the current user owns the
 * $shout.
 *
 * @param $shout
 *   The shout object that we want to check.
 *
 * @return
 *   True if the shout is owned by the current user
 *
 */
function _shoutbox_is_user_owned($shout) {
  global $user;
  $user_owned = FALSE;
  if ($shout->uid > 0 && $shout->uid == $user->uid) {
    $user_owned = TRUE;
  }
  else {
    if ($shout->uid == 0 && $user->uid == 0) {
      if ($shout->sid == session_id()) {
        $user_owned = TRUE;
      }
      else {
        if (empty($shout->sid) && !empty($shout->hostname)) {
          $user_owned = $shout->hostname == ip_address();
        }
      }
    }
  }
  return $user_owned;
}

Functions

Namesort descending Description
shoutbox_add_form Generates form for adding shouts.
shoutbox_add_form_submit Handles submission of a shout. Handles both ajax submission and regular form submission.
shoutbox_add_form_validate Makes sure uses don't submit default values.
shoutbox_admin_settings Form for admin/settings/shoutox page.
shoutbox_block Make the shout box block available. (Standard Drupal hook).
shoutbox_cron Implementation of hook_cron().
shoutbox_delete_form Displays a "Are you sure message ?" with a Yes and Cancel option.
shoutbox_delete_form_submit Handle the delete form submission.
shoutbox_edit_form Form for editing shouts.
shoutbox_edit_form_submit Handle the edit form submission.
shoutbox_help Describe the shoutbox module.
shoutbox_js_view Javascript callback. Prints out shouts only.
shoutbox_load Implementation of hook_load().
shoutbox_menu Implementation of hook_menu().
shoutbox_page_view Show paged view of full list of shouts.
shoutbox_perm Implementation of hook_perm().
shoutbox_publish_form Displays a "Are you sure message ?" with a Yes and Cancel option.
shoutbox_publish_form_submit Handle the publish form submission.
shoutbox_simpletest Implementation of hook_simpletest().
shoutbox_theme Implementation of hook_theme().
shoutbox_unpublish_form Displays a "Are you sure message ?" with a Yes and Cancel option.
shoutbox_unpublish_form_submit Handle the unpublish form submission.
shoutbox_user Implementation of hook_user().
theme_shoutbox_links Theme function of shoutbox actions. Actions are edit, delete, promote and demote. NOTE: Function does not return html but rather an array with the actions as keys. See code.
theme_shoutbox_page Theme function for displaying the shoutbox page.
theme_shoutbox_post Theme function for shoutbox posts.
theme_shoutbox_post_forbidden Theme function for displaying the access denied message.
_shoutbox_block_view Returns the themed HTML to be displayed in the block.
_shoutbox_display_posts Output existing shoutbox posts as html. Used by shoutbox_get_view.
_shoutbox_filter_form
_shoutbox_get_links Returns an array containing the possible actions for the current user based on permissions and shout. The actions are edit, delete, moderate.
_shoutbox_is_user_owned Determine if the current user owns the $shout.
_shoutbox_moderate_shout Update the moderate bit in the database.
_shoutbox_sanitize_shout This function cleans the shout object before it is used.
_shoutbox_user_access This function is necessary because even if a user has permission (according to the user_access function), they still should not have some permissions, such as moderating their own posts, etc.