<?php
// $Id: whois.module,v 1.20.2.4 2010/03/30 08:35:52 helmo Exp $


/**
 * Implementation of hook_perm().
 */
function whois_perm() {
  return array('access whois');
}

/**
 * Implementation of hook_theme().
 */
function whois_theme() {
  return array(
    'whois_domain_status' => array(
      'template' => 'whois_domain_status',
      'arguments' => array(
        'address' => NULL,      // The address that was looked up
        'registered' => NULL,   // Boolean, weather the domain is already registered
        'result_data' => NULL,  // Full result data, optionally used in template to further customise the output
      ),
    ),
  );
}

/**
 * Implementation of hook_menu().
 */
function whois_menu() {
  $items = array();

  $items['whois'] = array(
    'title' => 'Whois lookup',
    'page callback' => 'whois_whois_page',
    'access arguments' => array('access whois'),
    'file' => 'whois.pages.inc',
    'type' => MENU_NORMAL_ITEM,
  );
  $items['whois-ajax'] = array(
    'title' => 'Whois lookup',
    'page callback' => 'whois_ajax',
    'access arguments' => array('access whois'),
    'type' => MENU_CALLBACK,
  );
  $items['admin/settings/whois'] = array(
    'title' => 'Whois lookup',
    'description' => 'Configure Whois lookup output style, dynamic(AJAX) results, hourly threshold, and more.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('whois_settings'),
    'file' => 'whois.admin.inc',
    'access arguments' => array('administer site configuration'),
    'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

/**
 * Implementation of hook_block().
 */
function whois_block($op = 'list', $delta = 0) {

  // listing of blocks, such as on the admin/block page
  if ($op == "list") {
    $block[0]["info"] = t('Whois mini form');
    return $block;
  }
  elseif ($op == 'view') {

    switch ($delta) {
      case 0:
        $block['subject'] = 'Whois';
        $block_content = drupal_get_form('whois_whois_mini_form');
        break;
      }
    $block['content'] = $block_content;
    return $block;
  }
} // end whois_block

/**
 * Implementation of hook_form().
 *
 * Produce a form for the mini_form block
 */
function whois_whois_mini_form() {
  $form = array();

  $form['whois_address'] = array(
    '#type' => 'textfield',
    '#size' => 15,
    '#required' => TRUE,
  );
  $form['whois_submit'] = array(
    '#type' => 'submit',
    '#value' => t('Lookup'),
  );

  return $form;
}

/*
 *  Wrapper around whois_whois_form_submit
 */
function whois_whois_mini_form_submit($form, &$form_state) {
  module_load_include('inc', 'whois', 'whois.pages');
  whois_whois_form_submit($form, $form_state);
  return;
}

function whois_ajax() {
  if (!user_access('access whois')) {
    return;
  }

  $output = '';
  $address = !empty($_POST['address']) ? $_POST['address'] : arg(1);

  if (isset($address)) {
    // Check for hourly threshold.
    if (flood_is_allowed('whois', variable_get('whois_hourly_threshold', 13))) {
      $output .= whois_display_whois($address);
    }
    else {
      $output .= t("You cannot do more than %number whois lookups per hour. Please try again later.", array('%number' => variable_get('whois_hourly_threshold', 13)));
    }
    // Avoid debug information(devel.module) from being added to the preview.
    $GLOBALS['devel_shutdown'] = FALSE;

    // Stop further processing and return requested data.
    drupal_json(array('html' => $output));
  }
}

function whois_display_whois($address) {
  $data = '';
  $result = whois_get_whois($address);
  $allowed_tags = array('a', 'b', 'i', 'br');
  if ($result) {
    switch (variable_get('whois_output_method', 'html')) {
      case 'html':
        $data .= '<h3>' . t('Whois lookup for %address:', array('%address' => $address)) . '</h3>';
        if (!empty($result['whois_cached_on'])) {
          $data .= "<p id='whois_cached_on'>" . t('Cached on:') . ' ' . format_date($result['whois_cached_on'], 'large') . "</p>";
        }
        if (!empty($result['rawdata'])) {
          $mod_path = drupal_get_path('module', 'whois');
          include_once($mod_path . '/phpwhois/whois.main.php');
          include_once($mod_path . '/phpwhois/whois.utils.php');
          $utils = new utils;
          $data .= filter_xss(_whois_utf8_encode($utils->showHTML($result), $address), $allowed_tags);
        }
        else {
          $data .= _whois_handle_error($result, $address);
        }
        break;

      case 'html_status':
        if (!empty($result['rawdata'])) {
          $data .= theme('whois_domain_status', $address, $result['regrinfo']['registered'] != 'no', $result);
        }
        else {
          $data .= _whois_handle_error($result, $address);
        }
      break;

      case 'object':
        $data .= '<h3>' . t('Whois lookup for %address:', array('%address' => $address)) . '</h3>';
        if ($whois->Query['status'] < 0) {
          $data .= _whois_handle_error($result, $address);
        }
        else {
          $mod_path = drupal_get_path('module', 'whois');
          include_once($mod_path . '/phpwhois/whois.main.php');
          include_once($mod_path . '/phpwhois/whois.utils.php');
          $utils = new utils;
          $data .= '<pre>' . filter_xss(_whois_utf8_encode($utils->showObject($result), $address), $allowed_tags) . '</pre>';
        }
      break;

      case 'basic': // 'basic' is the default
      default:
        $data .= '<h3>' . t('Whois lookup for %address:', array('%address' => $address)) . '</h3>';
        if (!empty($result['rawdata'])) {
          $data .= '<pre>' . check_plain(_whois_utf8_encode(implode("\n", $result['rawdata']), $address)) . '</pre>';
        }
        else {
          $data .= _whois_handle_error($result, $address);
        }
      break;
    }
  }

  return $data;
}

/**
 * Return the whois information for a given host.
 *
 * @param $address
 *   The address of the host to look up.
 *
 * @return
 *   An object describing the Whois result.
 */
function whois_get_whois($address) {
  $data = '';
  $mod_path = drupal_get_path('module', 'whois');

  if (!file_exists($mod_path . '/phpwhois/whois.main.php')) {
    drupal_set_message(t('There are problems with <em>Whois lookup</em> setup. Report to the website administrators promptly!', array('@status' => url('admin/reports/status'))), 'error');
  }
  elseif ($address != '') {
    $address = _whois_cleanup_address($address);
    // check cache first
    $cid = 'whois-' . $address;
    if (variable_get('whois_cache_enable', 1) && ($cache = cache_get($cid, "cache")) && !empty($cache->data)) {
      if (variable_get('whois_log_watchdog', 1) && variable_get('whois_log_watchdog_cached', 0) ) {
        // Watchdog entry for lookup request if logging cached lookup also.
        watchdog('whois',
          'Whois lookup(cached) for: @address',
          array('@address' => $address),
          WATCHDOG_NOTICE, l('View', "whois/$address") . ' · ' . l('Address', "http://$address/"));
      }
      $cache->data['whois_cached_on'] = $cache->created;
      return $cache->data;
    }
    else {
      include_once($mod_path . '/phpwhois/whois.main.php');
      include_once($mod_path . '/phpwhois/whois.utils.php');
      $whois = new Whois();
      if (variable_get('whois_log_watchdog', 1)) {
        // Watchdog entry for lookup request.
        watchdog('whois',
          'Whois lookup for: @address',
          array('@address' => $address),
          WATCHDOG_NOTICE, l('View', "whois/$address") . ' · ' . l('Address', "http://$address/"));
      }
      $result = $whois->Lookup($address);


      if (empty($result) || empty($result['rawdata'])) {
        $result['error_query'] = $whois->Query;
      }
      elseif (variable_get('whois_cache_enable', 1)) {
        // cache results
        cache_set($cid, $result, "cache", variable_get("whois_cache_time", 86400));
      }
      return $result;
    }
  }
  return FALSE;
}

/**
 * Parse the user input to remove some obvious mistakes.
 * Elements like http:// are removed
 *
 * @param $address
 *   The user input
 *
 * @return
 *   The cleaned up domain or IP to look up
 */
function _whois_cleanup_address($address) {

  $r  = "^(?:(?P<scheme>\w+)://)?";             // e.g. http://
  $r .= "(?:(?P<login>\w+):(?P<pass>\w+)@)?";   // e.g. username:password@

  $r .= "(?:(?P<host>www\.(?=.*\..*)))?";    // e.g. www. the (?= is a lookahead to avoid removing www.com

  // The interresting part we would like to preserve
  // Matching very broad to avoid excluding things like IDN
  $r .= "(?P<domain>.+\.(?P<extension>.+))";  // e.g. www and example.com

  $r .= "(?::(?P<port>\d+))?";                  // e.g. :80
  $r .= "(?P<path>/[\w/]*(?P<file>\w+(?:\.\w+)?)?)?";   // e.g. /foo/bar/baz.html
  $r .= "(?:\?(?P<arg>[\w=&]+))?";              // e.g. ?foo=1&bar=2
  $r .= "(?:#(?P<anchor>\w+))?";                // e.g. #anchor42
  $r = "!$r!";                                  // Delimiters

  $result = array();
  preg_match($r, $address, $result);

  if (!empty($address) && empty($result['domain'])) {
    drupal_set_message(t("Invalid address received."), 'error');
  }
  elseif ($address != $result['domain']) {
    drupal_set_message(t("Reduced '%address' to '%new.'", array('%address' => $address, '%new' => $result['domain'])));
  }

  return $result['domain'];
}

/**
 * Detect the text encoding and encode it to UTF-8 when needed
 *
 * @param $str
 *   The text to encode
 *
 * @param $address
 *   The address being looked up
 *
 * @return
 *   The text encoded as UTF-8
 */
function _whois_utf8_encode(&$str, $address) {
  $encoding = mb_detect_encoding($str);

  // When a non-utf-8 encoding is detected, force an encoding.
  if ($encoding != 'UTF-8') {
    $str = utf8_encode($str);
  }
  return $str;
}

/**
 * Format and check the error data returned from the phpwhois library
 *
 * @param &$result
 *   The result array
 *
 * @param $address
 *   The address being looked up
 *
 * @return
 *   The error text encoded as UTF-8
 */
function _whois_handle_error(&$result, $address) {
  $str = '';

  if (is_array($result['error_query']['errstr'])) {
    $str .= implode("\n<br />", $result['error_query']['errstr']);
  }
  elseif (!empty($result['error_query']['errstr'])) {
    $str .= $result['error_query']['errstr'];
  }
  else {
    $str .= t("No data was retreived from whois server");
  }
  $str = check_plain(_whois_utf8_encode($str, $address));
  return $str;
}
