--- link.module
+++ link.module
@@ -1,734 +1,735 @@
-<?php
-// $Id: link.module,v 1.24.4.8 2009/11/05 04:09:07 jcfiala Exp $
-
-/**
- * @file
- * Defines simple link field types.
- */
-
-define('LINK_EXTERNAL', 'external');
-define('LINK_INTERNAL', 'internal');
-define('LINK_FRONT', 'front');
-define('LINK_EMAIL', 'email');
-define('LINK_DOMAINS', 'aero|arpa|asia|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|local');
-
-define('LINK_TARGET_DEFAULT', 'default');
-define('LINK_TARGET_NEW_WINDOW', '_blank');
-define('LINK_TARGET_TOP', '_top');
-define('LINK_TARGET_USER', 'user');
-
-/**
- * Implementation of hook_field_info().
- */
-function link_field_info() {
-  return array(
-    'link' => array(
-      'label' => t('Link'),
-      'description' => t('Store a title, href, and attributes in the database to assemble a link.'),
-    ),
-  );
-}
-
-/**
- * Implementation of hook_field_settings().
- */
-function link_field_settings($op, $field) {
-  switch ($op) {
-    case 'form':
-      $form = array(
-        '#theme' => 'link_field_settings',
-      );
-
-      $form['url'] = array(
-        '#type' => 'checkbox',
-        '#title' => t('Optional URL'),
-        '#default_value' => $field['url'],
-        '#return_value' => 'optional',
-        '#description' => t('If checked, the URL field is optional and submitting a title alone will be acceptable. If the URL is ommitted, the title will be displayed as plain text.'),
-      );
-
-      $title_options = array(
-        'optional' => t('Optional Title'),
-        'required' => t('Required Title'),
-        'value' => t('Static Title: '),
-        'none' => t('No Title'),
-      );
-
-      $form['title'] = array(
-        '#type' => 'radios',
-        '#title' => t('Link Title'),
-        '#default_value' => isset($field['title']) ? $field['title'] : 'optional',
-        '#options' => $title_options,
-        '#description' => t('If the link title is optional or required, a field will be displayed to the end user. If the link title is static, the link will always use the same title. If <a href="http://drupal.org/project/token">token module</a> is installed, the static title value may use any other node field as its value. Static and token-based titles may include most inline XHTML tags such as <em>strong</em>, <em>em</em>, <em>img</em>, <em>span</em>, etc.'),
-      );
-
-      $form['title_value'] = array(
-        '#type' => 'textfield',
-        '#default_value' => $field['title_value'],
-        '#size' => '46',
-      );
-
-      // Add token module replacements if available
-      if (module_exists('token')) {
-        $form['tokens'] = array(
-          '#type' => 'fieldset',
-          '#collapsible' => TRUE,
-          '#collapsed' => TRUE,
-          '#title' => t('Placeholder tokens'),
-          '#description' => t("The following placeholder tokens can be used in both paths and titles. When used in a path or title, they will be replaced with the appropriate values."),
-        );
-        $form['tokens']['help'] = array(
-          '#value' => theme('token_help', 'node'),
-        );
-
-        $form['enable_tokens'] = array(
-          '#type' => 'checkbox',
-          '#title' => t('Allow user-entered tokens'),
-          '#default_value' => isset($field['enable_tokens']) ? $field['enable_tokens'] : 1,
-          '#description' => t('Checking will allow users to enter tokens in URLs and Titles on the node edit form. This does not affect the field settings on this page.'),
-        );
-      }
-
-      $form['display'] = array(
-        '#tree' => TRUE,
-      );
-      $form['display']['url_cutoff'] = array(
-        '#type' => 'textfield',
-        '#title' => t('URL Display Cutoff'),
-        '#default_value' => isset($field['display']['url_cutoff']) ? $field['display']['url_cutoff'] : '80',
-        '#description' => t('If the user does not include a title for this link, the URL will be used as the title. When should the link title be trimmed and finished with an elipsis (&hellip;)? Leave blank for no limit.'),
-        '#maxlength' => 3,
-        '#size' => 3,
-      );
-
-      $target_options = array(
-        LINK_TARGET_DEFAULT => t('Default (no target attribute)'),
-        LINK_TARGET_TOP => t('Open link in window root'),
-        LINK_TARGET_NEW_WINDOW => t('Open link in new window'),
-        LINK_TARGET_USER => t('Allow the user to choose'),
-      );
-      $form['attributes'] = array(
-        '#tree' => TRUE,
-      );
-      $form['attributes']['target'] = array(
-        '#type' => 'radios',
-        '#title' => t('Link Target'),
-        '#default_value' => empty($field['attributes']['target']) ? LINK_TARGET_DEFAULT : $field['attributes']['target'],
-        '#options' => $target_options,
-      );
-      $form['attributes']['rel'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Rel Attribute'),
-        '#description' => t('When output, this link will have this rel attribute. The most common usage is <a href="http://en.wikipedia.org/wiki/Nofollow">rel=&quot;nofollow&quot;</a> which prevents some search engines from spidering entered links.'),
-        '#default_value' => empty($field['attributes']['rel']) ? '' : $field['attributes']['rel'],
-        '#field_prefix' => 'rel = "',
-        '#field_suffix' => '"',
-        '#size' => 20,
-      );
-      $form['attributes']['class'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Additional CSS Class'),
-        '#description' => t('When output, this link will have have this class attribute. Multiple classes should be separated by spaces.'),
-        '#default_value' => empty($field['attributes']['class']) ? '' : $field['attributes']['class'],
-      );
-      return $form;
-
-    case 'validate':
-      if ($field['title'] == 'value' && empty($field['title_value'])) {
-        form_set_error('title_value', t('A default title must be provided if the title is a static value'));
-      }
-      break;
-
-    case 'save':
-      return array('attributes', 'display', 'url', 'title', 'title_value', 'enable_tokens');
-
-    case 'database columns':
-      return array(
-        'url' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE),
-        'title' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE),
-        'attributes' => array('type' => 'text', 'size' => 'medium', 'not null' => FALSE),
-      );
-
-    case 'views data':
-      module_load_include('inc', 'link', 'views/link.views');
-      return link_views_content_field_data($field);
-  }
-}
-
-/**
- * Theme the settings form for the link field.
- */
-function theme_link_field_settings($form) {
-  $title_value = drupal_render($form['title_value']);
-  $title_checkbox = drupal_render($form['title']['value']);
-
-  // Set Static Title radio option to include the title_value textfield.
-  $form['title']['value'] = array('#value' => '<div class="container-inline">'. $title_checkbox . $title_value .'</div>');
-
-  // Reprint the title radio options with the included textfield.
-  return drupal_render($form);
-}
-
-/**
- * Implementation of hook_content_is_empty().
- */
-function link_content_is_empty($item, $field) {
-  if (empty($item['title']) && empty($item['url'])) {
-    return TRUE;
-  }
-  return FALSE;
-}
-
-/**
- * Implementation of hook_field().
- */
-function link_field($op, &$node, $field, &$items, $teaser, $page) {
-  switch ($op) {
-    case 'load':
-      return _link_load($field, $items);
-
-    case 'validate':
-      $optional_field_found = FALSE;
-      foreach ($items as $delta => $value) {
-        _link_validate($items[$delta], $delta, $field, $node, $optional_field_found);
-      }
-
-      if ($field['url'] == 'optional' && $field['title'] == 'optional' && $field['required'] && !$optional_field_found) {
-        form_set_error($field['field_name'] .'][0][title', t('At least one title or URL must be entered.'));
-      }
-      break;
-
-    case 'presave':
-      foreach ($items as $delta => $value) {
-        _link_process($items[$delta], $delta, $field, $node);
-      }
-      break;
-
-    case 'sanitize':
-      foreach ($items as $delta => $value) {
-        _link_sanitize($items[$delta], $delta, $field, $node);
-      }
-      break;
-  }
-}
-
-/**
- * Implementation of hook_widget_info().
- */
-function link_widget_info() {
-  return array(
-    'link' => array(
-      'label' => 'Link',
-      'field types' => array('link'),
-      'multiple values' => CONTENT_HANDLE_CORE,
-    ),
-  );
-}
-
-/**
- * Implementation of hook_widget().
- */
-function link_widget(&$form, &$form_state, $field, $items, $delta = 0) {
-  $element = array(
-    '#type' => $field['widget']['type'],
-    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
-    '#title' => $field['widget']['label'],
-    '#weight' => $field['widget']['weight'],
-    '#description' => $field['widget']['description'],
-    '#required' => $field['required'],
-    '#field' => $field,
-  );
-  return $element;
-}
-
-function _link_load($field, &$items) {
-  foreach ($items as $delta => $item) {
-    // Unserialize the attributes array.
-    $items[$delta]['attributes'] = unserialize($item['attributes']);
-  }
-  return array($field['field_name'] => $items);
-}
-
-function _link_process(&$item, $delta = 0, $field, $node) {
-  // Trim whitespace from URL.
-  $item['url'] = trim($item['url']);
-
-  // if no attributes are set use the default attributes.
-  if (empty($item['attributes'])) {
-    $item['attributes'] = _link_default_attributes();
-  }
-
-  // Serialize the attributes array.
-  $item['attributes'] = serialize($item['attributes']);
-
-  // Don't save an invalid default value (e.g. 'http://').
-  if ((isset($field['widget']['default_value'][$delta]['url']) && $item['url'] == $field['widget']['default_value'][$delta]['url']) && is_object($node)) {
-    if (!link_validate_url($item['url'])) {
-      unset($item['url']);
-    }
-  }
-}
-
-function _link_validate(&$item, $delta, $field, $node, &$optional_field_found) {
-  if ($item['url'] && !(isset($field['widget']['default_value'][$delta]['url']) && $item['url'] == $field['widget']['default_value'][$delta]['url'] && !$field['required'])) {
-    // Validate the link.
-    if (link_validate_url(trim($item['url'])) == FALSE) {
-      form_set_error($field['field_name'] .']['. $delta .'][url', t('Not a valid URL.'));
-    }
-    // Require a title for the link if necessary.
-    if ($field['title'] == 'required' && strlen(trim($item['title'])) == 0) {
-      form_set_error($field['field_name'] .']['. $delta .'][title', t('Titles are required for all links.'));
-    }
-  }
-  // Require a link if we have a title.
-  if ($field['url'] !== 'optional' && strlen($item['title']) > 0 && strlen(trim($item['url'])) == 0) {
-    form_set_error($field['field_name'] .']['. $delta .'][url', t('You cannot enter a title without a link url.'));
-  }
-  // In a totally bizzaro case, where URLs and titles are optional but the field is required, ensure there is at least one link.
-  if ($field['url'] == 'optional' && $field['title'] == 'optional' && (strlen(trim($item['url'])) != 0 || strlen(trim($item['title'])) != 0)) {
-    $optional_field_found = TRUE;
-  }
-}
-
-/**
- * Cleanup user-entered values for a link field according to field settings.
- *
- * @param $item
- *   A single link item, usually containing url, title, and attributes.
- * @param $delta
- *   The delta value if this field is one of multiple fields.
- * @param $field
- *   The CCK field definition.
- * @param $node
- *   The node containing this link.
- */
-function _link_sanitize(&$item, $delta, &$field, &$node) {
-  // Don't try to process empty links.
-  if (empty($item['url']) && empty($item['title'])) {
-    return;
-  }
-
-  // Replace URL tokens.
-  if (module_exists('token') && $field['enable_tokens']) {
-    // Load the node if necessary for nodes in views.
-    $token_node = isset($node->nid) ? node_load($node->nid) : $node;
-    $item['url'] = token_replace($item['url'], 'node', $token_node);
-  }
-
-  $type = link_validate_url($item['url']);
-  $url = link_cleanup_url($item['url']);
-
-  // Separate out the anchor if any.
-  if (strpos($url, '#') !== FALSE) {
-    $item['fragment'] = substr($url, strpos($url, '#') + 1);
-    $url = substr($url, 0, strpos($url, '#'));
-  }
-  // Separate out the query string if any.
-  if (strpos($url, '?') !== FALSE) {
-    $item['query'] = substr($url, strpos($url, '?') + 1);
-    $url = substr($url, 0, strpos($url, '?'));
-  }
-  // Save the new URL without the anchor or query.
-  $item['url'] = $url;
-
-  // Create a shortened URL for display.
-  $display_url = $type == LINK_EMAIL ? str_replace('mailto:', '', $url) : url($url, array('query' => isset($item['query']) ? $item['query'] : NULL, 'fragment' => isset($item['fragment']) ? $item['fragment'] : NULL, 'absolute' => TRUE));
-  if ($field['display']['url_cutoff'] && strlen($display_url) > $field['display']['url_cutoff']) {
-    $display_url = substr($display_url, 0, $field['display']['url_cutoff']) ."...";
-  }
-  $item['display_url'] = $display_url;
-
-  // Use the title defined at the field level.
-  if ($field['title'] == 'value' && strlen(trim($field['title_value']))) {
-    $title = $field['title_value'];
-  }
-  // Use the title defined by the user at the widget level.
-  else {
-    $title = $item['title'];
-  }
-  // Replace tokens.
-  if (module_exists('token') && ($field['title'] == 'value' || $field['enable_tokens'])) {
-    // Load the node if necessary for nodes in views.
-    $token_node = isset($node->nid) ? node_load($node->nid) : $node;
-    $title = filter_xss(token_replace($title, 'node', $token_node), array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
-    $item['html'] = TRUE;
-  }
-  $item['display_title'] = empty($title) ? $item['display_url'] : $title;
-
-  if (!isset($item['attributes'])) {
-    $item['attributes'] = array();
-  }
-
-  // Unserialize attributtes array if it has not been unserialized yet.
-  if (!is_array($item['attributes'])) {
-    $item['attributes'] = (array)unserialize($item['attributes']);
-  }
-
-  // Add default attributes.
-  $field['attributes'] += _link_default_attributes();
-
-  // Merge item attributes with attributes defined at the field level.
-  $item['attributes'] += $field['attributes'];
-
-  // If user is not allowed to choose target attribute, use default defined at
-  // field level.
-  if ($field['attributes']['target'] != LINK_TARGET_USER) {
-    $item['attributes']['target'] = $field['attributes']['target'];
-  }
-
-  // Remove the target attribute if the default (no target) is selected.
-  if (empty($item['attributes']) || $item['attributes']['target'] == LINK_TARGET_DEFAULT) {
-    unset($item['attributes']['target']);
-  }
-
-  // Remove the rel=nofollow for internal links.
-  if ($type != LINK_EXTERNAL && strpos($item['attributes']['rel'], 'nofollow') !== FALSE) {
-    $item['attributes']['rel'] = str_replace('nofollow', '', $item['attributes']);
-  }
-
-  // Remove empty attributes.
-  $item['attributes'] = array_filter($item['attributes']);
-
-  // Add the widget label.
-  $item['label'] = $field['widget']['label'];
-}
-
-/**
- * Implementation of hook_theme().
- */
-function link_theme() {
-  return array(
-    'link_field_settings' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'link_formatter_default' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'link_formatter_plain' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'link_formatter_url' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'link_formatter_short' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'link_formatter_label' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'link_formatter_separate' => array(
-      'arguments' => array('element' => NULL),
-    ),
-    'link' => array(
-      'arguments' => array('element' => NULL),
-    ),
-  );
-}
-
-/**
- * FAPI theme for an individual text elements.
- */
-function theme_link($element) {
-  drupal_add_css(drupal_get_path('module', 'link') .'/link.css');
-
-  // Prefix single value link fields with the name of the field.
-  if (empty($element['#field']['multiple'])) {
-    if (isset($element['url']) && isset($element['title'])) {
-      $element['url']['#title'] = $element['#title'] .' '. $element['url']['#title'];
-      $element['title']['#title'] = $element['#title'] .' '. $element['title']['#title'];
-    }
-    elseif ($element['url']) {
-      $element['url']['#title'] = $element['#title'];
-    }
-  }
-
-  $output = '';
-  $output .= '<div class="link-field-subrow clear-block">';
-  if (isset($element['title'])) {
-    $output .= '<div class="link-field-title link-field-column">'. theme('textfield', $element['title']) .'</div>';
-  }
-  $output .= '<div class="link-field-url'. (isset($element['title']) ? ' link-field-column' : '') .'">'. theme('textfield', $element['url']) .'</div>';
-  $output .= '</div>';
-  if (!empty($element['attributes']['target'])) {
-    $output .= '<div class="link-attributes">'. theme('checkbox', $element['attributes']['target']) .'</div>';
-  }
-  return $output;
-}
-
-/**
- * Implementation of hook_elements().
- */
-function link_elements() {
-  $elements = array();
-  $elements['link'] =  array(
-    '#input' => TRUE,
-    '#process' => array('link_process'),
-  );
-  return $elements;
-}
-
-function _link_default_attributes() {
-  return array(
-    'target' => LINK_TARGET_DEFAULT,
-    'class' => '',
-    'rel' => '',
-  );
-}
-
-/**
- * Process the link type element before displaying the field.
- *
- * Build the form element. When creating a form using FAPI #process,
- * note that $element['#value'] is already set.
- *
- * The $fields array is in $form['#field_info'][$element['#field_name']].
- */
-function link_process($element, $edit, $form_state, $form) {
-   $field = $form['#field_info'][$element['#field_name']];
-   $delta = $element['#delta'];
-   $element['url'] = array(
-     '#type' => 'textfield',
-     '#maxlength' => '255',
-     '#title' => t('URL'),
-     '#description' => $element['#description'],
-     '#required' => ($delta == 0 && $field['url'] !== 'optional') ? $element['#required'] : FALSE,
-     '#default_value' => isset($element['#value']['url']) ? $element['#value']['url'] : NULL,
-   );
-   if ($field['title'] != 'none' && $field['title'] != 'value') {
-     $element['title'] = array(
-       '#type' => 'textfield',
-       '#maxlength' => '255',
-       '#title' => t('Title'),
-       '#required' => ($delta == 0 && $field['title'] == 'required') ? $field['required'] : FALSE,
-       '#default_value' => isset($element['#value']['title']) ? $element['#value']['title'] : NULL,
-     );
-   }
-
-   // Initialize field attributes as an array if it is not an array yet.
-   if (!is_array($field['attributes'])) {
-     $field['attributes'] = array();
-   }
-   // Add default atrributes.
-   $field['attributes'] += _link_default_attributes();
-   $attributes = isset($element['#value']['attributes']) ? $element['#value']['attributes'] : $field['attributes'];
-   if (!empty($field['attributes']['target']) && $field['attributes']['target'] == LINK_TARGET_USER) {
-     $element['attributes']['target'] = array(
-       '#type' => 'checkbox',
-       '#title' => t('Open URL in a New Window'),
-       '#return_value' => LINK_TARGET_NEW_WINDOW,
-       '#default_value' => $attributes['target'],
-     );
-   }
-   return $element;
-}
-
-/**
- * Implementation of hook_field_formatter_info().
- */
-function link_field_formatter_info() {
-  return array(
-    'default' => array(
-      'label' => t('Title, as link (default)'),
-      'field types' => array('link'),
-      'multiple values' => CONTENT_HANDLE_CORE,
-    ),
-    'url' => array(
-      'label' => t('URL, as link'),
-      'field types' => array('link'),
-      'multiple values' => CONTENT_HANDLE_CORE,
-    ),
-    'plain' => array(
-      'label' => t('URL, as plain text'),
-      'field types' => array('link'),
-      'multiple values' => CONTENT_HANDLE_CORE,
-    ),
-    'short' => array(
-      'label' => t('Short, as link with title "Link"'),
-      'field types' => array('link'),
-      'multiple values' => CONTENT_HANDLE_CORE,
-    ),
-    'label' => array(
-      'label' => t('Label, as link with label as title'),
-      'field types' => array('link'),
-      'multiple values' => CONTENT_HANDLE_CORE,
-    ),
-    'separate' => array(
-      'label' => t('Separate title and URL'),
-      'field types' => array('link'),
-      'multiple values' => CONTENT_HANDLE_CORE,
-    ),
-  );
-}
-
-/**
- * Theme function for 'default' text field formatter.
- */
-function theme_link_formatter_default($element) {
-  // Display a normal link if both title and URL are available.
-  if (!empty($element['#item']['display_title']) && !empty($element['#item']['url'])) {
-    return l($element['#item']['display_title'], $element['#item']['url'], $element['#item']);
-  }
-  // If only a title, display the title.
-  elseif (!empty($element['#item']['display_title'])) {
-    return check_plain($element['#item']['display_title']);
-  }
-}
-
-/**
- * Theme function for 'plain' text field formatter.
- */
-function theme_link_formatter_plain($element) {
-  return empty($element['#item']['url']) ? check_plain($element['#item']['title']) : url($element['#item']['url'], $element['#item']);
-}
-
-/**
- * Theme function for 'url' text field formatter.
- */
-function theme_link_formatter_url($element) {
-  return $element['#item']['url'] ? l($element['#item']['display_url'], $element['#item']['url'], $element['#item']) : '';
-}
-
-/**
- * Theme function for 'short' text field formatter.
- */
-function theme_link_formatter_short($element) {
-  return $element['#item']['url'] ? l(t('Link'), $element['#item']['url'], $element['#item']) : '';
-}
-
-/**
- * Theme function for 'label' text field formatter.
- */
-function theme_link_formatter_label($element) {
-  return $element['#item']['url'] ? l($element['#item']['label'], $element['#item']['url'], $element['#item']) : '';
-}
-
-/**
- * Theme function for 'separate' text field formatter.
- */
-function theme_link_formatter_separate($element) {
-  $class = empty($element['#item']['attributes']['class']) ? '' : ' '. $element['#item']['attributes']['class'];
-  unset($element['#item']['attributes']['class']);
-  $title = empty($element['#item']['title']) ? '' : check_plain($element['#item']['title']);
-
-  $output = '';
-  $output .= '<div class="link-item '. $class .'">';
-  if (!empty($title)) {
-    $output .= '<div class="link-title">'. $title .'</div>';
-  }
-  $output .= '<div class="link-url">'. l($element['#item']['display_url'], $element['#item']['url'], $element['#item']) .'</div>';
-  $output .= '</div>';
-  return $output;
-}
-
-function link_token_list($type = 'all') {
-  if ($type == 'field' || $type == 'all') {
-    $tokens = array();
-
-    $tokens['link']['url'] = t("Link URL");
-    $tokens['link']['title'] = t("Link title");
-    $tokens['link']['view'] = t("Formatted html link");
-
-    return $tokens;
-  }
-}
-
-function link_token_values($type, $object = NULL) {
-  if ($type == 'field') {
-    $item = $object[0];
-
-    $tokens['url'] = $item['url'];
-    $tokens['title'] = $item['title'];
-    $tokens['view'] = isset($item['view']) ? $item['view'] : '';
-
-    return $tokens;
-  }
-}
-
-/**
- * Implementation of hook_views_api().
- */
-function link_views_api() {
-  return array(
-    'api' => 2,
-    'path' => drupal_get_path('module', 'link') .'/views',
-  );
-}
-
-/**
- * Forms a valid URL if possible from an entered address.
- * Trims whitespace and automatically adds an http:// to addresses without a protocol specified
- *
- * @param string $url
- * @param string $protocol The protocol to be prepended to the url if one is not specified
- */
-function link_cleanup_url($url, $protocol = "http") {
-  $url = trim($url);
-  $type = link_validate_url($url);
-
-  if ($type == LINK_EXTERNAL) {
-    // Check if there is no protocol specified.
-    $protocol_match = preg_match("/^([a-z0-9][a-z0-9\.\-_]*:\/\/)/i", $url);
-    if (empty($protocol_match)) {
-      // But should there be? Add an automatic http:// if it starts with a domain name.
-      $domain_match = preg_match('/^(([a-z0-9]([a-z0-9\-_]*\.)+)('. LINK_DOMAINS .'|[a-z]{2}))/i', $url);
-      if (!empty($domain_match)) {
-        $url = $protocol ."://". $url;
-      }
-    }
-  }
-
-  return $url;
-}
-
-/**
- * A lenient verification for URLs. Accepts all URLs following RFC 1738 standard
- * for URL formation and all email addresses following the RFC 2368 standard for
- * mailto address formation.
- *
- * @param string $text
- * @return mixed Returns boolean FALSE if the URL is not valid. On success, returns an object with
- * the following attributes: protocol, hostname, ip, and port.
- */
-function link_validate_url($text) {
-
-  $allowed_protocols = variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'));
-
-  $protocol = '(('. implode("|", $allowed_protocols) .'):\/\/)';
-  $authentication = '([a-z0-9]+(:[a-z0-9]+)?@)';
-  $domain = '(([a-z0-9]([a-z0-9\-_\[\]])*)(\.(([a-z0-9\-_\[\]])+\.)*('. LINK_DOMAINS .'|[a-z]{2}))?)';
-  $ipv4 = '([0-9]{1,3}(\.[0-9]{1,3}){3})';
-  $ipv6 = '([0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})';
-  $port = '(:([0-9]{1,5}))';
-
-  // Pattern specific to eternal links.
-  $external_pattern = '/^'. $protocol .'?'. $authentication .'?('. $domain .'|'. $ipv4 .'|'. $ipv6 .' |localhost)'. $port .'?';
-
-  // Pattern specific to internal links.
-  $internal_pattern = "/^([a-z0-9_\-+\[\]]+)";
-
-  $directories = "(\/[a-z0-9_\-\.~+%=&,$'!():;*@\[\]]*)*";
-  // Yes, four backslashes == a single backslash.
-  $query = "(\/?\?([?a-z0-9+_|\-\.\/\\\\%=&,$'():;*@\[\]]*))";
-  $anchor = "(#[a-z0-9_\-\.~+%=&,$'():;*@\[\]]*)";
-
-  // The rest of the path for a standard URL.
-  $end = $directories .'?'. $query .'?'. $anchor .'?'.'$/i';
-
-  $user = '[a-zA-Z0-9_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\'\[\]]+';
-  $email_pattern = '/^mailto:'. $user .'@'.'('. $domain .'|'. $ipv4 .'|'. $ipv6 .'|localhost)'. $query .'?$/';
-
-  if (strpos($text, '<front>') === 0) {
-    return LINK_FRONT;
-  }
-  if (in_array('mailto', $allowed_protocols) && preg_match($email_pattern, $text)) {
-    return LINK_EMAIL;
-  }
-  if (preg_match($internal_pattern . $end, $text)) {
-    return LINK_INTERNAL;
-  }
-  if (preg_match($external_pattern . $end, $text)) {
-    return LINK_EXTERNAL;
-  }
-
-  return FALSE;
-}
+<?php
+// $Id: link.module,v 1.24.4.8 2009/11/05 04:09:07 jcfiala Exp $
+
+/**
+ * @file
+ * Defines simple link field types.
+ */
+
+define('LINK_EXTERNAL', 'external');
+define('LINK_INTERNAL', 'internal');
+define('LINK_FRONT', 'front');
+define('LINK_EMAIL', 'email');
+define('LINK_DOMAINS', 'aero|arpa|asia|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|local');
+
+define('LINK_TARGET_DEFAULT', 'default');
+define('LINK_TARGET_NEW_WINDOW', '_blank');
+define('LINK_TARGET_TOP', '_top');
+define('LINK_TARGET_USER', 'user');
+
+/**
+ * Implementation of hook_field_info().
+ */
+function link_field_info() {
+  return array(
+    'link' => array(
+      'label' => t('Link'),
+      'description' => t('Store a title, href, and attributes in the database to assemble a link.'),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_field_settings().
+ */
+function link_field_settings($op, $field) {
+  switch ($op) {
+    case 'form':
+      $form = array(
+        '#theme' => 'link_field_settings',
+      );
+
+      $form['url'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Optional URL'),
+        '#default_value' => $field['url'],
+        '#return_value' => 'optional',
+        '#description' => t('If checked, the URL field is optional and submitting a title alone will be acceptable. If the URL is ommitted, the title will be displayed as plain text.'),
+      );
+
+      $title_options = array(
+        'optional' => t('Optional Title'),
+        'required' => t('Required Title'),
+        'value' => t('Static Title: '),
+        'none' => t('No Title'),
+      );
+
+      $form['title'] = array(
+        '#type' => 'radios',
+        '#title' => t('Link Title'),
+        '#default_value' => isset($field['title']) ? $field['title'] : 'optional',
+        '#options' => $title_options,
+        '#description' => t('If the link title is optional or required, a field will be displayed to the end user. If the link title is static, the link will always use the same title. If <a href="http://drupal.org/project/token">token module</a> is installed, the static title value may use any other node field as its value. Static and token-based titles may include most inline XHTML tags such as <em>strong</em>, <em>em</em>, <em>img</em>, <em>span</em>, etc.'),
+		'#required' => TRUE,
+      );
+
+      $form['title_value'] = array(
+        '#type' => 'textfield',
+        '#default_value' => $field['title_value'],
+        '#size' => '46',
+      );
+
+      // Add token module replacements if available
+      if (module_exists('token')) {
+        $form['tokens'] = array(
+          '#type' => 'fieldset',
+          '#collapsible' => TRUE,
+          '#collapsed' => TRUE,
+          '#title' => t('Placeholder tokens'),
+          '#description' => t("The following placeholder tokens can be used in both paths and titles. When used in a path or title, they will be replaced with the appropriate values."),
+        );
+        $form['tokens']['help'] = array(
+          '#value' => theme('token_help', 'node'),
+        );
+
+        $form['enable_tokens'] = array(
+          '#type' => 'checkbox',
+          '#title' => t('Allow user-entered tokens'),
+          '#default_value' => isset($field['enable_tokens']) ? $field['enable_tokens'] : 1,
+          '#description' => t('Checking will allow users to enter tokens in URLs and Titles on the node edit form. This does not affect the field settings on this page.'),
+        );
+      }
+
+      $form['display'] = array(
+        '#tree' => TRUE,
+      );
+      $form['display']['url_cutoff'] = array(
+        '#type' => 'textfield',
+        '#title' => t('URL Display Cutoff'),
+        '#default_value' => isset($field['display']['url_cutoff']) ? $field['display']['url_cutoff'] : '80',
+        '#description' => t('If the user does not include a title for this link, the URL will be used as the title. When should the link title be trimmed and finished with an elipsis (&hellip;)? Leave blank for no limit.'),
+        '#maxlength' => 3,
+        '#size' => 3,
+      );
+
+      $target_options = array(
+        LINK_TARGET_DEFAULT => t('Default (no target attribute)'),
+        LINK_TARGET_TOP => t('Open link in window root'),
+        LINK_TARGET_NEW_WINDOW => t('Open link in new window'),
+        LINK_TARGET_USER => t('Allow the user to choose'),
+      );
+      $form['attributes'] = array(
+        '#tree' => TRUE,
+      );
+      $form['attributes']['target'] = array(
+        '#type' => 'radios',
+        '#title' => t('Link Target'),
+        '#default_value' => empty($field['attributes']['target']) ? LINK_TARGET_DEFAULT : $field['attributes']['target'],
+        '#options' => $target_options,
+      );
+      $form['attributes']['rel'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Rel Attribute'),
+        '#description' => t('When output, this link will have this rel attribute. The most common usage is <a href="http://en.wikipedia.org/wiki/Nofollow">rel=&quot;nofollow&quot;</a> which prevents some search engines from spidering entered links.'),
+        '#default_value' => empty($field['attributes']['rel']) ? '' : $field['attributes']['rel'],
+        '#field_prefix' => 'rel = "',
+        '#field_suffix' => '"',
+        '#size' => 20,
+      );
+      $form['attributes']['class'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Additional CSS Class'),
+        '#description' => t('When output, this link will have have this class attribute. Multiple classes should be separated by spaces.'),
+        '#default_value' => empty($field['attributes']['class']) ? '' : $field['attributes']['class'],
+      );
+      return $form;
+
+    case 'validate':
+      if ($field['title'] == 'value' && empty($field['title_value'])) {
+        form_set_error('title_value', t('A default title must be provided if the title is a static value'));
+      }
+      break;
+
+    case 'save':
+      return array('attributes', 'display', 'url', 'title', 'title_value', 'enable_tokens');
+
+    case 'database columns':
+      return array(
+        'url' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE),
+        'title' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE),
+        'attributes' => array('type' => 'text', 'size' => 'medium', 'not null' => FALSE),
+      );
+
+    case 'views data':
+      module_load_include('inc', 'link', 'views/link.views');
+      return link_views_content_field_data($field);
+  }
+}
+
+/**
+ * Theme the settings form for the link field.
+ */
+function theme_link_field_settings($form) {
+  $title_value = drupal_render($form['title_value']);
+  $title_checkbox = drupal_render($form['title']['value']);
+
+  // Set Static Title radio option to include the title_value textfield.
+  $form['title']['value'] = array('#value' => '<div class="container-inline">'. $title_checkbox . $title_value .'</div>');
+
+  // Reprint the title radio options with the included textfield.
+  return drupal_render($form);
+}
+
+/**
+ * Implementation of hook_content_is_empty().
+ */
+function link_content_is_empty($item, $field) {
+  if (empty($item['title']) && empty($item['url'])) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Implementation of hook_field().
+ */
+function link_field($op, &$node, $field, &$items, $teaser, $page) {
+  switch ($op) {
+    case 'load':
+      return _link_load($field, $items);
+
+    case 'validate':
+      $optional_field_found = FALSE;
+      foreach ($items as $delta => $value) {
+        _link_validate($items[$delta], $delta, $field, $node, $optional_field_found);
+      }
+
+      if ($field['url'] == 'optional' && $field['title'] == 'optional' && $field['required'] && !$optional_field_found) {
+        form_set_error($field['field_name'] .'][0][title', t('At least one title or URL must be entered.'));
+      }
+      break;
+
+    case 'presave':
+      foreach ($items as $delta => $value) {
+        _link_process($items[$delta], $delta, $field, $node);
+      }
+      break;
+
+    case 'sanitize':
+      foreach ($items as $delta => $value) {
+        _link_sanitize($items[$delta], $delta, $field, $node);
+      }
+      break;
+  }
+}
+
+/**
+ * Implementation of hook_widget_info().
+ */
+function link_widget_info() {
+  return array(
+    'link' => array(
+      'label' => 'Link',
+      'field types' => array('link'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_widget().
+ */
+function link_widget(&$form, &$form_state, $field, $items, $delta = 0) {
+  $element = array(
+    '#type' => $field['widget']['type'],
+    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
+    '#title' => $field['widget']['label'],
+    '#weight' => $field['widget']['weight'],
+    '#description' => $field['widget']['description'],
+    '#required' => $field['required'],
+    '#field' => $field,
+  );
+  return $element;
+}
+
+function _link_load($field, &$items) {
+  foreach ($items as $delta => $item) {
+    // Unserialize the attributes array.
+    $items[$delta]['attributes'] = unserialize($item['attributes']);
+  }
+  return array($field['field_name'] => $items);
+}
+
+function _link_process(&$item, $delta = 0, $field, $node) {
+  // Trim whitespace from URL.
+  $item['url'] = trim($item['url']);
+
+  // if no attributes are set use the default attributes.
+  if (empty($item['attributes'])) {
+    $item['attributes'] = _link_default_attributes();
+  }
+
+  // Serialize the attributes array.
+  $item['attributes'] = serialize($item['attributes']);
+
+  // Don't save an invalid default value (e.g. 'http://').
+  if ((isset($field['widget']['default_value'][$delta]['url']) && $item['url'] == $field['widget']['default_value'][$delta]['url']) && is_object($node)) {
+    if (!link_validate_url($item['url'])) {
+      unset($item['url']);
+    }
+  }
+}
+
+function _link_validate(&$item, $delta, $field, $node, &$optional_field_found) {
+  if ($item['url'] && !(isset($field['widget']['default_value'][$delta]['url']) && $item['url'] == $field['widget']['default_value'][$delta]['url'] && !$field['required'])) {
+    // Validate the link.
+    if (link_validate_url(trim($item['url'])) == FALSE) {
+      form_set_error($field['field_name'] .']['. $delta .'][url', t('Not a valid URL.'));
+    }
+    // Require a title for the link if necessary.
+    if ($field['title'] == 'required' && strlen(trim($item['title'])) == 0) {
+      form_set_error($field['field_name'] .']['. $delta .'][title', t('Titles are required for all links.'));
+    }
+  }
+  // Require a link if we have a title.
+  if ($field['url'] !== 'optional' && strlen($item['title']) > 0 && strlen(trim($item['url'])) == 0) {
+    form_set_error($field['field_name'] .']['. $delta .'][url', t('You cannot enter a title without a link url.'));
+  }
+  // In a totally bizzaro case, where URLs and titles are optional but the field is required, ensure there is at least one link.
+  if ($field['url'] == 'optional' && $field['title'] == 'optional' && (strlen(trim($item['url'])) != 0 || strlen(trim($item['title'])) != 0)) {
+    $optional_field_found = TRUE;
+  }
+}
+
+/**
+ * Cleanup user-entered values for a link field according to field settings.
+ *
+ * @param $item
+ *   A single link item, usually containing url, title, and attributes.
+ * @param $delta
+ *   The delta value if this field is one of multiple fields.
+ * @param $field
+ *   The CCK field definition.
+ * @param $node
+ *   The node containing this link.
+ */
+function _link_sanitize(&$item, $delta, &$field, &$node) {
+  // Don't try to process empty links.
+  if (empty($item['url']) && empty($item['title'])) {
+    return;
+  }
+
+  // Replace URL tokens.
+  if (module_exists('token') && $field['enable_tokens']) {
+    // Load the node if necessary for nodes in views.
+    $token_node = isset($node->nid) ? node_load($node->nid) : $node;
+    $item['url'] = token_replace($item['url'], 'node', $token_node);
+  }
+
+  $type = link_validate_url($item['url']);
+  $url = link_cleanup_url($item['url']);
+
+  // Separate out the anchor if any.
+  if (strpos($url, '#') !== FALSE) {
+    $item['fragment'] = substr($url, strpos($url, '#') + 1);
+    $url = substr($url, 0, strpos($url, '#'));
+  }
+  // Separate out the query string if any.
+  if (strpos($url, '?') !== FALSE) {
+    $item['query'] = substr($url, strpos($url, '?') + 1);
+    $url = substr($url, 0, strpos($url, '?'));
+  }
+  // Save the new URL without the anchor or query.
+  $item['url'] = $url;
+
+  // Create a shortened URL for display.
+  $display_url = $type == LINK_EMAIL ? str_replace('mailto:', '', $url) : url($url, array('query' => isset($item['query']) ? $item['query'] : NULL, 'fragment' => isset($item['fragment']) ? $item['fragment'] : NULL, 'absolute' => TRUE));
+  if ($field['display']['url_cutoff'] && strlen($display_url) > $field['display']['url_cutoff']) {
+    $display_url = substr($display_url, 0, $field['display']['url_cutoff']) ."...";
+  }
+  $item['display_url'] = $display_url;
+
+  // Use the title defined at the field level.
+  if ($field['title'] == 'value' && strlen(trim($field['title_value']))) {
+    $title = $field['title_value'];
+  }
+  // Use the title defined by the user at the widget level.
+  else {
+    $title = $item['title'];
+  }
+  // Replace tokens.
+  if (module_exists('token') && ($field['title'] == 'value' || $field['enable_tokens'])) {
+    // Load the node if necessary for nodes in views.
+    $token_node = isset($node->nid) ? node_load($node->nid) : $node;
+    $title = filter_xss(token_replace($title, 'node', $token_node), array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
+    $item['html'] = TRUE;
+  }
+  $item['display_title'] = empty($title) ? $item['display_url'] : $title;
+
+  if (!isset($item['attributes'])) {
+    $item['attributes'] = array();
+  }
+
+  // Unserialize attributtes array if it has not been unserialized yet.
+  if (!is_array($item['attributes'])) {
+    $item['attributes'] = (array)unserialize($item['attributes']);
+  }
+
+  // Add default attributes.
+  $field['attributes'] += _link_default_attributes();
+
+  // Merge item attributes with attributes defined at the field level.
+  $item['attributes'] += $field['attributes'];
+
+  // If user is not allowed to choose target attribute, use default defined at
+  // field level.
+  if ($field['attributes']['target'] != LINK_TARGET_USER) {
+    $item['attributes']['target'] = $field['attributes']['target'];
+  }
+
+  // Remove the target attribute if the default (no target) is selected.
+  if (empty($item['attributes']) || $item['attributes']['target'] == LINK_TARGET_DEFAULT) {
+    unset($item['attributes']['target']);
+  }
+
+  // Remove the rel=nofollow for internal links.
+  if ($type != LINK_EXTERNAL && strpos($item['attributes']['rel'], 'nofollow') !== FALSE) {
+    $item['attributes']['rel'] = str_replace('nofollow', '', $item['attributes']);
+  }
+
+  // Remove empty attributes.
+  $item['attributes'] = array_filter($item['attributes']);
+
+  // Add the widget label.
+  $item['label'] = $field['widget']['label'];
+}
+
+/**
+ * Implementation of hook_theme().
+ */
+function link_theme() {
+  return array(
+    'link_field_settings' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'link_formatter_default' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'link_formatter_plain' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'link_formatter_url' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'link_formatter_short' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'link_formatter_label' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'link_formatter_separate' => array(
+      'arguments' => array('element' => NULL),
+    ),
+    'link' => array(
+      'arguments' => array('element' => NULL),
+    ),
+  );
+}
+
+/**
+ * FAPI theme for an individual text elements.
+ */
+function theme_link($element) {
+  drupal_add_css(drupal_get_path('module', 'link') .'/link.css');
+
+  // Prefix single value link fields with the name of the field.
+  if (empty($element['#field']['multiple'])) {
+    if (isset($element['url']) && isset($element['title'])) {
+      $element['url']['#title'] = $element['#title'] .' '. $element['url']['#title'];
+      $element['title']['#title'] = $element['#title'] .' '. $element['title']['#title'];
+    }
+    elseif ($element['url']) {
+      $element['url']['#title'] = $element['#title'];
+    }
+  }
+
+  $output = '';
+  $output .= '<div class="link-field-subrow clear-block">';
+  if (isset($element['title'])) {
+    $output .= '<div class="link-field-title link-field-column">'. theme('textfield', $element['title']) .'</div>';
+  }
+  $output .= '<div class="link-field-url'. (isset($element['title']) ? ' link-field-column' : '') .'">'. theme('textfield', $element['url']) .'</div>';
+  $output .= '</div>';
+  if (!empty($element['attributes']['target'])) {
+    $output .= '<div class="link-attributes">'. theme('checkbox', $element['attributes']['target']) .'</div>';
+  }
+  return $output;
+}
+
+/**
+ * Implementation of hook_elements().
+ */
+function link_elements() {
+  $elements = array();
+  $elements['link'] =  array(
+    '#input' => TRUE,
+    '#process' => array('link_process'),
+  );
+  return $elements;
+}
+
+function _link_default_attributes() {
+  return array(
+    'target' => LINK_TARGET_DEFAULT,
+    'class' => '',
+    'rel' => '',
+  );
+}
+
+/**
+ * Process the link type element before displaying the field.
+ *
+ * Build the form element. When creating a form using FAPI #process,
+ * note that $element['#value'] is already set.
+ *
+ * The $fields array is in $form['#field_info'][$element['#field_name']].
+ */
+function link_process($element, $edit, $form_state, $form) {
+   $field = $form['#field_info'][$element['#field_name']];
+   $delta = $element['#delta'];
+   $element['url'] = array(
+     '#type' => 'textfield',
+     '#maxlength' => '255',
+     '#title' => t('URL'),
+     '#description' => $element['#description'],
+     '#required' => ($delta == 0 && $field['url'] !== 'optional') ? $element['#required'] : FALSE,
+     '#default_value' => isset($element['#value']['url']) ? $element['#value']['url'] : NULL,
+   );
+   if ($field['title'] != 'none' && $field['title'] != 'value') {
+     $element['title'] = array(
+       '#type' => 'textfield',
+       '#maxlength' => '255',
+       '#title' => t('Title'),
+       '#required' => ($delta == 0 && $field['title'] == 'required') ? $field['required'] : FALSE,
+       '#default_value' => isset($element['#value']['title']) ? $element['#value']['title'] : NULL,
+     );
+   }
+
+   // Initialize field attributes as an array if it is not an array yet.
+   if (!is_array($field['attributes'])) {
+     $field['attributes'] = array();
+   }
+   // Add default atrributes.
+   $field['attributes'] += _link_default_attributes();
+   $attributes = isset($element['#value']['attributes']) ? $element['#value']['attributes'] : $field['attributes'];
+   if (!empty($field['attributes']['target']) && $field['attributes']['target'] == LINK_TARGET_USER) {
+     $element['attributes']['target'] = array(
+       '#type' => 'checkbox',
+       '#title' => t('Open URL in a New Window'),
+       '#return_value' => LINK_TARGET_NEW_WINDOW,
+       '#default_value' => $attributes['target'],
+     );
+   }
+   return $element;
+}
+
+/**
+ * Implementation of hook_field_formatter_info().
+ */
+function link_field_formatter_info() {
+  return array(
+    'default' => array(
+      'label' => t('Title, as link (default)'),
+      'field types' => array('link'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+    'url' => array(
+      'label' => t('URL, as link'),
+      'field types' => array('link'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+    'plain' => array(
+      'label' => t('URL, as plain text'),
+      'field types' => array('link'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+    'short' => array(
+      'label' => t('Short, as link with title "Link"'),
+      'field types' => array('link'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+    'label' => array(
+      'label' => t('Label, as link with label as title'),
+      'field types' => array('link'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+    'separate' => array(
+      'label' => t('Separate title and URL'),
+      'field types' => array('link'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+  );
+}
+
+/**
+ * Theme function for 'default' text field formatter.
+ */
+function theme_link_formatter_default($element) {
+  // Display a normal link if both title and URL are available.
+  if (!empty($element['#item']['display_title']) && !empty($element['#item']['url'])) {
+    return l($element['#item']['display_title'], $element['#item']['url'], $element['#item']);
+  }
+  // If only a title, display the title.
+  elseif (!empty($element['#item']['display_title'])) {
+    return check_plain($element['#item']['display_title']);
+  }
+}
+
+/**
+ * Theme function for 'plain' text field formatter.
+ */
+function theme_link_formatter_plain($element) {
+  return empty($element['#item']['url']) ? check_plain($element['#item']['title']) : url($element['#item']['url'], $element['#item']);
+}
+
+/**
+ * Theme function for 'url' text field formatter.
+ */
+function theme_link_formatter_url($element) {
+  return $element['#item']['url'] ? l($element['#item']['display_url'], $element['#item']['url'], $element['#item']) : '';
+}
+
+/**
+ * Theme function for 'short' text field formatter.
+ */
+function theme_link_formatter_short($element) {
+  return $element['#item']['url'] ? l(t('Link'), $element['#item']['url'], $element['#item']) : '';
+}
+
+/**
+ * Theme function for 'label' text field formatter.
+ */
+function theme_link_formatter_label($element) {
+  return $element['#item']['url'] ? l($element['#item']['label'], $element['#item']['url'], $element['#item']) : '';
+}
+
+/**
+ * Theme function for 'separate' text field formatter.
+ */
+function theme_link_formatter_separate($element) {
+  $class = empty($element['#item']['attributes']['class']) ? '' : ' '. $element['#item']['attributes']['class'];
+  unset($element['#item']['attributes']['class']);
+  $title = empty($element['#item']['title']) ? '' : check_plain($element['#item']['title']);
+
+  $output = '';
+  $output .= '<div class="link-item '. $class .'">';
+  if (!empty($title)) {
+    $output .= '<div class="link-title">'. $title .'</div>';
+  }
+  $output .= '<div class="link-url">'. l($element['#item']['display_url'], $element['#item']['url'], $element['#item']) .'</div>';
+  $output .= '</div>';
+  return $output;
+}
+
+function link_token_list($type = 'all') {
+  if ($type == 'field' || $type == 'all') {
+    $tokens = array();
+
+    $tokens['link']['url'] = t("Link URL");
+    $tokens['link']['title'] = t("Link title");
+    $tokens['link']['view'] = t("Formatted html link");
+
+    return $tokens;
+  }
+}
+
+function link_token_values($type, $object = NULL) {
+  if ($type == 'field') {
+    $item = $object[0];
+
+    $tokens['url'] = $item['url'];
+    $tokens['title'] = $item['title'];
+    $tokens['view'] = isset($item['view']) ? $item['view'] : '';
+
+    return $tokens;
+  }
+}
+
+/**
+ * Implementation of hook_views_api().
+ */
+function link_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'link') .'/views',
+  );
+}
+
+/**
+ * Forms a valid URL if possible from an entered address.
+ * Trims whitespace and automatically adds an http:// to addresses without a protocol specified
+ *
+ * @param string $url
+ * @param string $protocol The protocol to be prepended to the url if one is not specified
+ */
+function link_cleanup_url($url, $protocol = "http") {
+  $url = trim($url);
+  $type = link_validate_url($url);
+
+  if ($type == LINK_EXTERNAL) {
+    // Check if there is no protocol specified.
+    $protocol_match = preg_match("/^([a-z0-9][a-z0-9\.\-_]*:\/\/)/i", $url);
+    if (empty($protocol_match)) {
+      // But should there be? Add an automatic http:// if it starts with a domain name.
+      $domain_match = preg_match('/^(([a-z0-9]([a-z0-9\-_]*\.)+)('. LINK_DOMAINS .'|[a-z]{2}))/i', $url);
+      if (!empty($domain_match)) {
+        $url = $protocol ."://". $url;
+      }
+    }
+  }
+
+  return $url;
+}
+
+/**
+ * A lenient verification for URLs. Accepts all URLs following RFC 1738 standard
+ * for URL formation and all email addresses following the RFC 2368 standard for
+ * mailto address formation.
+ *
+ * @param string $text
+ * @return mixed Returns boolean FALSE if the URL is not valid. On success, returns an object with
+ * the following attributes: protocol, hostname, ip, and port.
+ */
+function link_validate_url($text) {
+
+  $allowed_protocols = variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'));
+
+  $protocol = '(('. implode("|", $allowed_protocols) .'):\/\/)';
+  $authentication = '([a-z0-9]+(:[a-z0-9]+)?@)';
+  $domain = '(([a-z0-9]([a-z0-9\-_\[\]])*)(\.(([a-z0-9\-_\[\]])+\.)*('. LINK_DOMAINS .'|[a-z]{2}))?)';
+  $ipv4 = '([0-9]{1,3}(\.[0-9]{1,3}){3})';
+  $ipv6 = '([0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})';
+  $port = '(:([0-9]{1,5}))';
+
+  // Pattern specific to eternal links.
+  $external_pattern = '/^'. $protocol .'?'. $authentication .'?('. $domain .'|'. $ipv4 .'|'. $ipv6 .' |localhost)'. $port .'?';
+
+  // Pattern specific to internal links.
+  $internal_pattern = "/^([a-z0-9_\-+\[\]]+)";
+
+  $directories = "(\/[a-z0-9_\-\.~+%=&,$'!():;*@\[\]]*)*";
+  // Yes, four backslashes == a single backslash.
+  $query = "(\/?\?([?a-z0-9+_|\-\.\/\\\\%=&,$'():;*@\[\]]*))";
+  $anchor = "(#[a-z0-9_\-\.~+%=&,$'():;*@\[\]]*)";
+
+  // The rest of the path for a standard URL.
+  $end = $directories .'?'. $query .'?'. $anchor .'?'.'$/i';
+
+  $user = '[a-zA-Z0-9_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\'\[\]]+';
+  $email_pattern = '/^mailto:'. $user .'@'.'('. $domain .'|'. $ipv4 .'|'. $ipv6 .'|localhost)'. $query .'?$/';
+
+  if (strpos($text, '<front>') === 0) {
+    return LINK_FRONT;
+  }
+  if (in_array('mailto', $allowed_protocols) && preg_match($email_pattern, $text)) {
+    return LINK_EMAIL;
+  }
+  if (preg_match($internal_pattern . $end, $text)) {
+    return LINK_INTERNAL;
+  }
+  if (preg_match($external_pattern . $end, $text)) {
+    return LINK_EXTERNAL;
+  }
+
+  return FALSE;
+}
