<?php
/* $Id: print.module,v 1.15.2.5.2.29.2.14 2008/01/25 11:27:35 jcnventura Exp $ */

/**
 * @file
 * Display printer-friendly versions of Drupal pages
 */

define("PRINT_PATH", "print");

/********************************************************************
 * Drupal Hooks
 ********************************************************************/

/**
 * Implementation of hook_perm()
 */
function print_perm() {
  return array('access print', 'administer print');
}

/**
 * Implementation of hook_menu()
 */
function print_menu($may_cache) {
  $items = array();

  if ($may_cache) {
    $items[] = array(
      'path' => PRINT_PATH,
      'title' => t('Printer-friendly'),
      'callback' => 'print_controller',
      'access' => user_access('access print'),
      'type' => MENU_CALLBACK
    );
    $items[] = array(
      'path' => 'admin/settings/print',
      'title' => t('Printer-friendly'),
      'description' => t('Adds a printer-friendly version link to node pages.'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array('print_main_settings'),
      'access'  => user_access('administer print'),
    );
  }

  return $items;
}

/**
 * Implementation of hook_link().
 */
function print_link($type, $node = NULL, $teaser = FALSE) {
  $print_settings = variable_get('print_settings', print_settings_default());
  // No link is shown for several motives...
  if ( !($teaser) && ($node->type != 'book') && (!$node->parent) &&
      ($print_settings['show_link']) && user_access('access print') &&
      (($type == 'comment' && variable_get('print_display_comment', '0')) ||
      ($type == 'node' && variable_get('print_display_'. $node->type, '1')))) {
    $links = array();

    $format = theme('print_format_link');

    if ($type == 'comment') {
      $query = "comment=$node->cid";
    }

    $links['print'] = array('href' => PRINT_PATH ."/". $node->nid,
                            'title' => $format['text'],
                            'attributes' => $format['attributes'],
                            'html' => $format['html'],
                            'query' => $query);

    return $links;
  } 
  else {
    return;
  }
}

/**
 * Implementation of hook_link_alter().
 */
function print_link_alter(&$node, &$links) {
  foreach ($links AS $module => $link) {
    if (strstr($module, 'book_printer')) {
      $print_settings = variable_get('print_settings', print_settings_default());

      if ($print_settings['book_link']) {
        $format = theme('print_format_link');
        $format['attributes']['title'] = $link['attributes']['title'];

        $links[$module]['href'] = PRINT_PATH ."/". $link['href'];
        $links[$module]['attributes'] = $format['attributes'];
      }
    }
  }
}

/**
 * Implementation of hook_help()
 */
function print_help($path) {
  $print_settings = variable_get('print_settings', print_settings_default());

  if (($print_settings['show_link']) && ($print_settings['show_sys_link']) &&
      user_access('access print') && (preg_match("/^node\//i", $path) == 0)) {
    static $output = FALSE;

    if ($output === FALSE) {
      $output = TRUE;
    
      return print_insert_link();
    }
  }
}

/**
 * Implementation of hook_form_alter()
 */
function print_form_alter($form_id, &$form) {
  // Add the node-type settings option to activate the printer-friendly version link
  if ('node_type_form' == $form_id) {
    $form['workflow']['print_display'] = array(
      '#type' => 'checkbox',
      '#title' => t('Show printer-friendly version link'),
      '#return_value' => 1,
      '#default_value' => variable_get('print_display_'. $form['#node_type']->type, '1'),
      '#description' => t('Displays the link to a printer-friendly version of the content. Further configuration is available on the !settings.', array('!settings' => l(t('settings page'), 'admin/settings/print' ))),
    );
  }
  elseif ('comment_admin_settings' == $form_id) {
    $form['viewing_options']['print_display_comment'] = array(
      '#type' => 'checkbox',
      '#title' => t('Show printer-friendly version link in individual comments'),
      '#return_value' => 1,
      '#default_value' => variable_get('print_display_comment', '0'),
      '#description' => t('Displays the link to a printer-friendly version of the comment. Further configuration is available on the !settings.', array('!settings' => l(t('settings page'), 'admin/settings/print' ))),
    );
  }
}

/********************************************************************
 * Admin Settings: Print
 ********************************************************************/

/**
 * Default values of the print_settings variable
 */
function print_settings_default() {
  return array('show_link' => 1, 'show_sys_link' => 1, 'book_link' => 1, 'logo_url' => '', 'css' => '', 'urls' => 1, 'comments' => 0, 'newwindow' => 0, 'sendtoprinter' => 0);
}

/**
 * Default values of the print_sourceurl_settings variable
 */
function print_sourceurl_settings_default() {
  return array('enabled' => 1, 'date' => 0, 'forcenode' => 0);
}

/**
 * Default values of the print_robot_settings variable
 */
function print_robot_settings_default() {
  return array('noindex' => 1, 'nofollow' => 1, 'noarchive' => 0, 'nocache' => 0);
}

/**
 * Print module settings form
 */
function print_main_settings() {
  $print_settings = variable_get('print_settings', print_settings_default());
  
  $form['print_settings'] = array(
      '#type' => 'fieldset',
      '#tree' => TRUE,
    );

  $form['print_settings']['show_link'] = array(
    '#type' => 'radios',
    '#title' => t('Printer-friendly page link'),
    '#default_value' => $print_settings['show_link'],
    '#options' => array(t("Disabled"), t("Enabled")),
    '#description' => t("Enable or disable the printer-friendly page link for each node. Even if the link is disabled, you can still view the print version of a node by going to print/nid where nid is the numeric id of the node."),
  );

  $form['print_settings']['show_sys_link'] = array(
    '#type' => 'checkbox',
    '#title' => t('Show link in system (non-content) pages'),
    '#return_value' => 1,
    '#default_value' => $print_settings['show_sys_link'],
    '#description' => t('Setting this option will add a printer-friendly version page link on pages created by Drupal or the enabled modules.'),
  );

  $form['print_settings']['book_link'] = array(
    '#type' => 'checkbox',
    '#title' => t('Take control of the book module printer-friendly link'),
    '#return_value' => 1,
    '#default_value' => $print_settings['book_link'],
    '#description' => t('Activate this to have the printer-friendly link in book nodes handled by this module. Requires the (core) book module.'),
  );

  $form['print_settings']['logo_url'] = array(
    '#type' => 'textfield',
    '#title' => t('Logo URL'),
    '#default_value' => $print_settings['logo_url'],
    '#size' => 60,
    '#maxlength' => 250,
    '#description' => t('An alternative logo to display on the printer-friendly version. If left empty, the current theme\'s logo is used.'),
  );

  $form['print_settings']['css'] = array(
    '#type' => 'textfield',
    '#title' => t('Stylesheet URL'),
    '#default_value' => $print_settings['css'],
    '#size' => 60,
    '#maxlength' => 64,
    '#description' => t('The URL to your custom print cascading stylesheet, if any. When none is specified, the default module CSS file is used.'),
  );

  $form['print_settings']['urls'] = array(
    '#type' => 'checkbox',
    '#title' => t('Printer-friendly URLs list'),
    '#return_value' => 1,
    '#default_value' => $print_settings['urls'],
    '#description' => t('If set, a list of the destination URLs for the page links will be displayed at the bottom of the page.'),
  );

  $form['print_settings']['comments'] = array(
    '#type' => 'checkbox',
    '#title' => t('Include comments in printer-friendly version'),
    '#return_value' => 1,
    '#default_value' => $print_settings['comments'],
    '#description' => t('When this option is active, user comments are also included in the printer-friendly version. Requires the comment module.'),
  );

  $form['print_settings']['newwindow'] = array(
    '#type' => 'radios',
    '#title' => t('Open the printer-friendly version in a new window'),
    '#options' => array(t("Disabled"), t("Use HTML target (does not validate as XHTML Strict)"), t("Use Javascript (requires browser support)")),
    '#default_value' => $print_settings['newwindow'],
    '#description' => t('Setting this option will make the printer-friendly version open in a new window/tab.'),
  );

  $form['print_settings']['sendtoprinter'] = array(
    '#type' => 'checkbox',
    '#title' => t('Send to printer'),
    '#return_value' => 1,
    '#default_value' => $print_settings['sendtoprinter'],
    '#description' => t('Automatically calls the browser\'s print function when the printer-friendly version is displayed.'),
  );

  $print_sourceurl_settings = variable_get('print_sourceurl_settings', print_sourceurl_settings_default());

  $form['print_sourceurl_settings'] = array(
      '#type' => 'fieldset',
      '#title' => t('Source URL'),
      '#collapsible' => true,
      '#collapsed' => true,
      '#tree' => true,
  );

  $form['print_sourceurl_settings']['enabled'] = array(
    '#type' => 'checkbox',
    '#title' => t('Display source URL'),
    '#return_value' => 1,
    '#default_value' => $print_sourceurl_settings['enabled'],
    '#description' => t('When this option is selected, the URL for the original page will be displayed at the bottom of the printer-friendly version.'),
  );

  $form['print_sourceurl_settings']['date'] = array(
    '#type' => 'checkbox',
    '#title' => t('Add current time/date to the source URL'),
    '#return_value' => 1,
    '#default_value' => $print_sourceurl_settings['date'],
    '#description' => t('Display the current date and time in the Source URL line.'),
  );

  $form['print_sourceurl_settings']['forcenode'] = array(
    '#type' => 'checkbox',
    '#title' => t('Force use of node ID in source URL'),
    '#return_value' => 1,
    '#default_value' => $print_sourceurl_settings['forcenode'],
    '#description' => t('Drupal will attempt to use the page\'s defined alias in case there is one. To force the use of the fixed URL, activate this option.'),
  );

  $print_robot_settings = variable_get('print_robot_settings', print_robot_settings_default());

  $form['print_robot_settings'] = array(
      '#type' => 'fieldset',
      '#title' => t('Robots META tags'),
      '#collapsible' => true,
      '#collapsed' => true,
      '#tree' => TRUE,
  );

  $form['print_robot_settings']['noindex'] = array(
    '#type' => 'checkbox',
    '#title' => t('Add noindex'),
    '#return_value' => 1,
    '#default_value' => $print_robot_settings['noindex'],
    '#description' => t('Instruct robots to not index printer-friendly pages. Recommended for good search engine karma.')
  );

  $form['print_robot_settings']['nofollow'] = array(
    '#type' => 'checkbox',
    '#title' => t('Add nofollow'),
    '#return_value' => 1,
    '#default_value' => $print_robot_settings['nofollow'],
    '#description' => t('Instruct robots to not follow outgoing links on printer-friendly pages.')
  );

  $form['print_robot_settings']['noarchive'] = array(
    '#type' => 'checkbox',
    '#title' => t('Add noarchive'),
    '#return_value' => 1,
    '#default_value' => $print_robot_settings['noarchive'],
    '#description' => t('Non-standard tag to instruct search engines to not show a "Cached" link for your printer-friendly pages. Recognized by Googlebot.')
  );

  $form['print_robot_settings']['nocache'] = array(
    '#type' => 'checkbox',
    '#title' => t('Add nocache'),
    '#return_value' => 1,
    '#default_value' => $print_robot_settings['nocache'],
    '#description' => t('Non-standard tag to instruct search engines to not show a "Cached" link for your printer-friendly pages')
  );

  return system_settings_form($form);
}

/********************************************************************
 * Module Functions :: Controller
 ********************************************************************/

/**
 * Print module path catcher
 */
function print_controller() {
  // Remove the print/ prefix
  $args = substr($_GET['q'], strlen(PRINT_PATH)+1);

  $cid = $_GET['comment'];

  $nid = $args;
  if (!is_numeric($nid)) {
    // Indirect call with print/alias
    // If there is a path alias with these arguments, generate a printer-friendly version for it
    $path = drupal_get_normal_path($args);
    $ret = preg_match("/^node\/(.*)/i", $path, $matches);
    if ($ret == 1) {
      $nid = $matches[1];
    }
  }
  if (is_numeric($nid)) {
    print_generate_node($nid, $cid);
  } 
  else {
    $ret = preg_match("/^book\/export\/html\/(.*)/i", $args, $matches);
    if ($ret == 1) {
      // This is a book PF page link, handle trough the book handling functions
      print_generate_book($matches[1]);
    }
    else {
      // If no content node was found, handle the page printing with the 'printable' engine
      print_generate_path($args);
    }
  }
}

/********************************************************************
 * Module Functions : Auxiliary
 ********************************************************************/

/**
 * Generates a meta tag to tell robots what they may index based on module settings
 *
 * @return string
 */
function _print_robots_meta_generator() {
  $robots_settings = variable_get('print_robot_settings', print_robot_settings_default());
  $robots_meta = array();

  if (!empty($robots_settings['noindex'])) {
    $robots_meta[] = 'noindex';
  }
  if (!empty($robots_settings['nofollow'])) {
    $robots_meta[] = 'nofollow';
  }
  if (!empty($robots_settings['noarchive'])) {
    $robots_meta[] = 'noarchive';
  }
  if (!empty($robots_settings['nocache'])) {
    $robots_meta[] = 'nocache';
  }

  if (sizeof($robots_meta) > 0) {
    $robots_meta = isset($robots_meta[1]) ? implode(', ', $robots_meta) : $robots_meta[0];
    $robots_meta = '<meta name="robots" content="'. $robots_meta ."\" />\n";
  } 
  else {
    $robots_meta = '';
  }

  return $robots_meta;
}

/**
 * Generates the HTML to insert in the template file
 *
 * @return string
 */
function _print_var_generator($node, $cid = NULL) {
  global $base_url;

  $themed = theme('print_text');

  // print module settings
  $print_settings = variable_get('print_settings', print_settings_default());
  $print_sourceurl_settings = variable_get('print_sourceurl_settings', print_sourceurl_settings_default());

  $print["language"] = $GLOBALS['locale'];
  $print["title"] = $node->title;
  $print["robots_meta"] = _print_robots_meta_generator();
//  $print["base_href"] = "<base href=\"".$base_url."/node/".$node->nid."\" />\n";
  $print["base_href"] = "<base href=\"". url("node/$node->nid", NULL, NULL, TRUE) ."\" />\n";
  $print["head"] = drupal_get_html_head();
  $print["favicon"] = theme_get_setting("toggle_favicon") ? "<link rel=\"shortcut icon\" href=\"". theme_get_setting("favicon") ."\" type=\"image/x-icon\"/>\n" : "";

  if (!empty($print_settings['css'])) {
    $print["css"] = "<style type=\"text/css\" media=\"all\">@import \"". $print_settings['css'] ."\";</style>\n";
  } 
  else {
    ob_start();
    include_once(drupal_get_path('module', 'print') ."/print.css");
    $print["css"] = "<style type=\"text/css\" media=\"all\">". ob_get_contents() ."</style>\n";
    ob_end_clean();
  }

  $print["sendtoprinter"] = $print_settings['sendtoprinter'] ? " onload=\"window.print();\"" : "";
    
  $print["logo"] = !empty($print_settings['logo_url']) ? $print_settings['logo_url'] : theme_get_setting('logo');
  $print["logo"] = $print["logo"] ? "<img class=\"print-logo\" src=\"". $print["logo"] ."\" alt=\"\" />\n" : "";

  /* Grab and format the src URL */
  if ($print_sourceurl_settings['enabled'] == 1) {
    if (empty($print_sourceurl_settings['forcenode'])) {
      $print["source_url"] = url("node/$node->nid", NULL, NULL, TRUE);
    } 
    else {
      $print["source_url"] = $base_url .'/'. (((bool)variable_get('clean_url', '0')) ? '' : '?q=') .'node/'. $node->nid;
    }
    if ($cid) {
      $print["source_url"] .= "#comment-$cid";
    }
    $print["printdate"] = $print_sourceurl_settings['date'] ? (" (". $themed['retrieved'] ." ". format_date(time(), 'small') .")") : "";
    $print["source_url"] = "<strong>". $themed['sourceURL'] . $print["printdate"] .":</strong> <a href=\"". $print["source_url"] ."\">". $print["source_url"] ."</a>";
  } 
  else {
    $print["source_url"] = "";
  }

  $print["site_name"] = variable_get('site_name', 0) ? ($themed['published'] ." ". variable_get('site_name', 0) ." (". l($base_url, $base_url) .")") : "";
  $print["submitted"] = theme_get_setting("toggle_node_info_$node->type") ? $themed['by'] ." ". ($node->name ? $node->name : variable_get('anonymous')) : "";
  $print["created"] = theme_get_setting("toggle_node_info_$node->type") ? $themed['created'] ." ". format_date($node->created, 'small') : "";

  // Display the collected links at the bottom of the page. Code once taken from Kjartan Mannes' project.module
  if (!empty($print_settings['urls'])) {
    $urls = print_friendly_urls();
    $max = count($urls);
    if ($max) {
      $print["pfp_links"] = '';
      for ($i = 0; $i < $max; $i++) {
        $print["pfp_links"] .= '['. ($i + 1) .'] '. $urls[$i] ."<br />\n";
      }
      $print["pfp_links"] = "<p><strong>". $themed['links'] ."</strong><br />". $print["pfp_links"] ."</p>";
    }
  }

  $print["footer_message"] = filter_xss_admin(variable_get('site_footer', FALSE)) ."\n". theme('blocks', 'footer') ;

  if (module_exists('taxonomy')) {
    $terms = taxonomy_link('taxonomy terms', $node);
    $print["taxonomy"] = theme('links', $terms);
  }

  return $print;
}

/**
 * We need to manipulate URLs so that they are recorded as absolute in the 
 *  Printer-friendly URLs list, and to add a [n] footnote marker.
 *
 * @return string containing the changed <a> tag
 */
function print_rewrite_urls($matches) {
  global $base_url;

  // Get value of Printer-friendly URLs setting
  $print_settings = variable_get('print_settings', print_settings_default());
  $pfurls = (!empty($print_settings['urls']));

  //Temporarily convert spaces to %20 so that it isn't split below
  $in_string = false; 
  for ($i=0; $i < strlen($matches[1]); $i++) {
    if ($matches[1][$i] == '"') {
      $in_string = !$in_string;
    }
    if (($matches[1][$i] == ' ') && ($in_string)) {
      $matches[1]=substr_replace($matches[1], "%20", $i, 1);
    }
  }

  // first, split the html into the different tag attributes
  $attribs = preg_split("/\s+/m", $matches[1]);

  for ($i=1; $i < count($attribs); $i++) {
    // If the attribute is href or src, we may need to rewrite the URL in the value
    if (preg_match("/^href|src/i", $attribs[$i]) > 0) {
      // We may need to rewrite the URL, so let's isolate it
      preg_match("/.*?=(.*)/is", $attribs[$i], $urls);
      $url = trim($urls[1], " \t\n\r\0\x0B\"\'");

      if (strpos($url, '://') || preg_match("/^mailto:.*?@.*?\..*?$/iu", $url)) {
        // URL is absolute, do nothing
        $newurl = urldecode($url);
      } 
      else {
        if (substr($url, 0, 1) == "#") {
          // URL is an anchor tag
          if ($pfurls) {
            $path = substr($_GET['q'], strlen(PRINT_PATH)+1);
            if (is_numeric($path)) {
              $path = "node/$path";
            }
            // Printer-friendly URLs is on, so we need to make it absolute
            $newurl = url($path, NULL, substr(urldecode($url), 1), TRUE);
          }
          // Because base href is the original page, change the link to
          // still be usable inside the print page
          $matches[1] = str_replace($url, $_GET['q'] . $url, $matches[1]);
        } 
        else {
          // URL is relative, convert it into absolute URL
          $clean_url = (bool)variable_get('clean_url', '0');
          if (substr($url, 0, 1) == "/") {
            // If it starts with '/' just append it to the server name
            $max = strpos($base_url, '/', 7);
            if ($max === false) {
              $server = $base_url;
            }
            else {
              $server = substr($base_url, 0, $max);
            }
            $newurl = $server .'/'. trim(urldecode($url), "/");
          }
          elseif ((!$clean_url) && (preg_match("/^[index.php]?\?q=.*/i", $url))) {
            // If Clean URLs is disabled, and it starts with q=?, just prepend with the base URL
            $newurl = $base_url .'/'. trim(urldecode($url), "/");
          } 
          else {
            $newurl = url(trim(urldecode($url), "/"), NULL, NULL, TRUE);
          }
          $matches[1] = str_replace($url, $newurl, $matches[1]);
        }
      }
    }
  }

  $ret = '<'. $matches[1] .'>';
  if ($attribs[0] == "a") {
    $ret .= $matches[2] .'</a>';
    if (($pfurls) && ($newurl)) {
      $ret .= ' <span class="print-footnote">['. print_friendly_urls(trim(stripslashes($newurl))) .']</span>';
    }
  }

  return $ret;
}

/**
 * Auxiliary function to store the Printer-friendly URLs list as static.
 *
 * @return string containing the list of URLs previously stored if $url is 0, 
 *         or the current count otherwise.
 */
function print_friendly_urls($url = 0) {
  static $urls = array();
  if ($url) {
    $urls[] = $url;
    return count($urls);
  }
  return $urls;
}

/**
 * Auxiliary function to fill the Printer-friendly link attributes
 *
 * @return array of formatted attributes
 */
function print_fill_attributes() {
  $print_settings = variable_get('print_settings', print_settings_default());
  $robots_settings = variable_get('print_robot_settings', print_robot_settings_default());

  $attributes = array('title' => t('Display a printer-friendly version of this page.'), 
                      'class' => 'print-page');
  switch ($print_settings['newwindow']) {
  case 1:
    $attributes['target'] = '_blank';
    break;
  case 2:
    $attributes['onclick'] = 'window.open(this.href); return false';
    break;
  }
  if (!empty($robots_settings['nofollow'])) {
    $attributes['rel'] = 'nofollow';
  }
  return $attributes;
}

function theme_print_format_link() {
  return array('text' => t('Printer-friendly version'),
               'html' => FALSE,
               'attributes' => print_fill_attributes());
}

function theme_print_text() {
  return array('retrieved' => t('retrieved on'),
               'sourceURL' => t('Source URL'),
               'published' => t('Published on'),
               'by' => t('By'),
               'created' => t('Created'),
               'links' => t('Links:'));
}

/**
 * Auxiliary function to display a formatted Printer-friendly link
 *
 * @return string
 */
function print_insert_link($path = NULL) {
  if (user_access('access print')) {
    if ($path === NULL) {
      $path = PRINT_PATH ."/". $_GET['q'];
      $query = drupal_query_string_encode($_GET, array('q'));
      if (empty($query)) {
        $query = NULL;
      }
    }
    $format = theme('print_format_link');
    return '<span class="print">'. l($format['text'], $path, $format['attributes'], $query, NULL, TRUE, $format['html']) .'</span>';
  }
}

/**
 * Auxiliary function to resolve the most appropriate template trying to find
 * a content specific template in the theme or module dir before falling back
 * on a generic template also in those dirs.
 *
 * @return string with the most suitable template filename
 */
function print_get_template($type = NULL) {
  if ($type) {
    // If the node type is known, then try to find that type's template file
    // First in the theme directory
    $filename = drupal_get_path('theme', $GLOBALS['theme_key']) ."/print.$type.tpl.php";
    if (file_exists($filename)) {
      return $filename;
    }
    // Then in the module directory
    $filename = drupal_get_path('module', 'print') ."/print.$type.tpl.php";
    if (file_exists($filename)) {
      return $filename;
    }
  }
  // Search for a generic template file
  // First in the theme directory
  $filename = drupal_get_path('theme', $GLOBALS['theme_key']) ."/print.tpl.php";
  if (file_exists($filename)) {
    return $filename;
  }
  // Then in the module directory
  // This one must always exist (provided with the module!)
  return drupal_get_path('module', 'print') ."/print.tpl.php";
}

/********************************************************************
 * Module Functions : Content renderers
 ********************************************************************/

/**
 * Outputs a printer-friendly page. Used for content types
 */
function print_generate_node($nid, $cid = NULL) {
  global $base_url;

  // We can take a node id
  $node = node_load(array('nid' => $nid));
  if (!node_access('view', $node)) {
    // Access is denied
    return drupal_access_denied();
  }

  //alert other modules that we are generating a printer-friendly page, so they can choose to show/hide info
  $node->printing = true;
  // Turn off Pagination by the Paging module
  unset($node->pages);
  unset($node->page_count);

  unset($node->teaser);
  $node = (object)$node;
  if ($cid === NULL) {
    // Adapted (simplified) version of node_view for Drupal 5.x
    //Render the node content
    $node = node_build_content($node, false, true);
    // Disable fivestar widget output
    unset($node->content["fivestar_widget"]);
    // Disable service links module output
    unset($node->content["service_links"]);
  
    $node->body = drupal_render($node->content);
  }

  $print_settings = variable_get('print_settings', print_settings_default());

  if (function_exists(comment_render) && (($cid != NULL) || ($print_settings['comments']))) {
    //Print only the requested comment (or if $cid is NULL, all of them)
    $comments = comment_render($node, $cid);
    
    //Remove the comment forms
    $comments = preg_replace("/<form.*?id=\"comment-.*?\">.*?<\/form>/sim", "", $comments);
    //Remove the 'Post new comment' title
    $comments = preg_replace("/<h2.*?>Post new comment<\/h2>/", "", $comments);
    //Remove the comment title hyperlink
    $comments = preg_replace("/(<h3.*?>)(<a.*?>)(.*?)<\/a>(<\/h3>)/", "$1$3$4", $comments);
    //Remove the comment links
    $comments = preg_replace("/\s*<div class=\"links\">.*?<\/div>/sim", "", $comments);
    if ($cid != NULL) {
      // Single comment requested, output only the comment
      unset($node->body);
    }
    $node->body .= $comments;
  }

  node_invoke_nodeapi($node, 'alter', false, true);

  // Convert the a href elements
  $pattern = "@<(a\s[^>]*?)>(.*?)</a>@is";
  $node->body = preg_replace_callback($pattern, "print_rewrite_urls", $node->body);

  init_theme();

  $print = _print_var_generator($node, $cid);

  include_once(print_get_template($node->type));
}

/**
 * Outputs a printer-friendly page. Used for drupal core pages.
 */
function print_generate_path($path) {
  global $base_url;

  $path = drupal_get_normal_path($path);

  menu_set_active_item($path);
  // Adapted from index.php.
  $node = new stdClass();
  $node->body = menu_execute_active_handler();

  // It may happen that a drupal_not_found is called in the above call
  if (preg_match('/404 Not Found/', drupal_get_headers()) == 1) {
    return;
  }

  switch ($node->body) {
  case MENU_NOT_FOUND:
    return drupal_not_found();
    break;
  case MENU_ACCESS_DENIED:
    return drupal_access_denied();
    break;
  }

  // Delete any links area
  $node->body = preg_replace("/\s*<div class=\"links\">.*?<\/div>/sim", "", $node->body);

  // Convert the a href elements
  $pattern = "@<(a\s[^>]*?)>(.*?)</a>@is";
  $node->body = preg_replace_callback($pattern, "print_rewrite_urls", $node->body);

  init_theme();

  $print = _print_var_generator($node);

  include_once(print_get_template());
}


/**
 * Outputs a printer-friendly page. Used for book pages
 */
function print_generate_book($nid) {
  global $base_url;

  $node = node_load(array('nid' => $nid));
  if (!node_access('view', $node) || (!user_access('see printer-friendly version'))) {
    // Access is denied
    return drupal_access_denied();
  }

  $depth = count(book_location($node)) + 1;
  $node->body = book_recurse($nid, $depth, 'print_node_visitor_html_pre', 'book_node_visitor_html_post');

  // Convert the a href elements
  $pattern = "@<(a\s[^>]*?)>(.*?)</a>@is";
  $node->body = preg_replace_callback($pattern, "print_rewrite_urls", $node->body);

  init_theme();

  $print = _print_var_generator($node);
  // The title is already displayed by the book_recurse, so avoid duplication
  $print["title"] = "";

  include_once(print_get_template($node->type));
}

/**
 * My own version of book_node_visitor_html_pre so that CCK pages in book nodes
 * come out right
 */
function print_node_visitor_html_pre($node, $depth, $nid) {
  $node = node_build_content($node);

  // Allow modules to make their own additions to the node.
  node_invoke_nodeapi($node, 'view');

  unset($node->content["book_navigation"]);

  $output .= "<div id=\"node-". $node->nid ."\" class=\"section-$depth\">\n";
  $output .= "<h1 class=\"book-heading\">". check_plain($node->title) ."</h1>\n";
  $output .= drupal_render($node->content);

  return $output;
}
