Browse Source

security updates
have to check views and entityreference for custom patches

Bachir Soussi Chiadmi 9 years ago
parent
commit
b3221c71e2
100 changed files with 5232 additions and 3722 deletions
  1. 1 1
      sites/all/modules/contrib/admin/context/README.txt
  2. 11 0
      sites/all/modules/contrib/admin/context/context.api.php
  3. 29 12
      sites/all/modules/contrib/admin/context/context.core.inc
  4. 3 3
      sites/all/modules/contrib/admin/context/context.info
  5. 1 0
      sites/all/modules/contrib/admin/context/context.install
  6. 7 1
      sites/all/modules/contrib/admin/context/context.module
  7. 54 2
      sites/all/modules/contrib/admin/context/context.plugins.inc
  8. 3 3
      sites/all/modules/contrib/admin/context/context_layouts/context_layouts.info
  9. 3 1
      sites/all/modules/contrib/admin/context/context_layouts/context_layouts.module
  10. 3 3
      sites/all/modules/contrib/admin/context/context_ui/context_ui.info
  11. 12 4
      sites/all/modules/contrib/admin/context/context_ui/context_ui.module
  12. 1 0
      sites/all/modules/contrib/admin/context/context_ui/export_ui/context_export_ui.class.php
  13. 1 0
      sites/all/modules/contrib/admin/context/context_ui/tests/context_ui.test
  14. 43 1
      sites/all/modules/contrib/admin/context/plugins/context_condition_context.inc
  15. 29 0
      sites/all/modules/contrib/admin/context/plugins/context_condition_context_all.inc
  16. 35 0
      sites/all/modules/contrib/admin/context/plugins/context_condition_default.inc
  17. 28 0
      sites/all/modules/contrib/admin/context/plugins/context_condition_query_string.inc
  18. 1 1
      sites/all/modules/contrib/admin/context/plugins/context_reaction_block.css
  19. 75 67
      sites/all/modules/contrib/admin/context/plugins/context_reaction_block.inc
  20. 1 6
      sites/all/modules/contrib/admin/context/plugins/context_reaction_block.js
  21. 26 26
      sites/all/modules/contrib/admin/context/plugins/context_reaction_breadcrumb.inc
  22. 15 1
      sites/all/modules/contrib/admin/context/plugins/context_reaction_debug.inc
  23. 85 84
      sites/all/modules/contrib/admin/context/plugins/context_reaction_menu.inc
  24. 47 0
      sites/all/modules/contrib/admin/context/plugins/context_reaction_template_suggestions.inc
  25. 30 5
      sites/all/modules/contrib/admin/context/tests/context.reactions.test
  26. 10 5
      sites/all/modules/contrib/admin/context/theme/context_reaction_block.theme.inc
  27. 3 54
      sites/all/modules/contrib/admin/print/INSTALL.txt
  28. 2 7
      sites/all/modules/contrib/admin/print/css/print-rtl.css
  29. 6 19
      sites/all/modules/contrib/admin/print/css/print.css
  30. BIN
      sites/all/modules/contrib/admin/print/icons/mail_icon.gif
  31. BIN
      sites/all/modules/contrib/admin/print/icons/pdf_icon.gif
  32. BIN
      sites/all/modules/contrib/admin/print/icons/print_icon.gif
  33. BIN
      sites/all/modules/contrib/admin/print/icons/print_icon.png
  34. 151 0
      sites/all/modules/contrib/admin/print/includes/print.drush.inc
  35. 100 0
      sites/all/modules/contrib/admin/print/includes/print.inc
  36. 21 196
      sites/all/modules/contrib/admin/print/print.admin.inc
  37. 122 0
      sites/all/modules/contrib/admin/print/print.api.php
  38. 6 10
      sites/all/modules/contrib/admin/print/print.info
  39. 70 34
      sites/all/modules/contrib/admin/print/print.install
  40. 113 724
      sites/all/modules/contrib/admin/print/print.module
  41. 342 313
      sites/all/modules/contrib/admin/print/print.pages.inc
  42. 95 22
      sites/all/modules/contrib/admin/print/print.tpl.php
  43. BIN
      sites/all/modules/contrib/admin/print/print_epub/icons/epub_icon.png
  44. 32 0
      sites/all/modules/contrib/admin/print/print_epub/lib_handlers/print_epub_phpepub/print_epub_phpepub.drush.inc
  45. 12 0
      sites/all/modules/contrib/admin/print/print_epub/lib_handlers/print_epub_phpepub/print_epub_phpepub.info
  46. 65 0
      sites/all/modules/contrib/admin/print/print_epub/lib_handlers/print_epub_phpepub/print_epub_phpepub.module
  47. 48 0
      sites/all/modules/contrib/admin/print/print_epub/lib_handlers/print_epub_phpepub/print_epub_phpepub.pages.inc
  48. 115 0
      sites/all/modules/contrib/admin/print/print_epub/print_epub.admin.inc
  49. 96 0
      sites/all/modules/contrib/admin/print/print_epub/print_epub.api.php
  50. 65 0
      sites/all/modules/contrib/admin/print/print_epub/print_epub.drush.inc
  51. 13 0
      sites/all/modules/contrib/admin/print/print_epub/print_epub.info
  52. 159 0
      sites/all/modules/contrib/admin/print/print_epub/print_epub.install
  53. 254 0
      sites/all/modules/contrib/admin/print/print_epub/print_epub.module
  54. 126 0
      sites/all/modules/contrib/admin/print/print_epub/print_epub.pages.inc
  55. 121 0
      sites/all/modules/contrib/admin/print/print_epub/print_epub.views.inc
  56. 5 3
      sites/all/modules/contrib/admin/print/print_join_page_counter.inc
  57. 3 0
      sites/all/modules/contrib/admin/print/print_mail/css/print_mail.theme-rtl.css
  58. 8 0
      sites/all/modules/contrib/admin/print/print_mail/css/print_mail.theme.css
  59. BIN
      sites/all/modules/contrib/admin/print/print_mail/icons/mail_icon.png
  60. 21 175
      sites/all/modules/contrib/admin/print/print_mail/print_mail.admin.inc
  61. 131 44
      sites/all/modules/contrib/admin/print/print_mail/print_mail.inc
  62. 4 9
      sites/all/modules/contrib/admin/print/print_mail/print_mail.info
  63. 45 22
      sites/all/modules/contrib/admin/print/print_mail/print_mail.install
  64. 104 398
      sites/all/modules/contrib/admin/print/print_mail/print_mail.module
  65. BIN
      sites/all/modules/contrib/admin/print/print_pdf/icons/pdf_icon.png
  66. 18 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/INSTALL.txt
  67. 38 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.admin.inc
  68. 32 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.drush.inc
  69. 13 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.info
  70. 16 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.install
  71. 95 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.module
  72. 158 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.pages.inc
  73. 32 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_mpdf/print_pdf_mpdf.drush.inc
  74. 12 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_mpdf/print_pdf_mpdf.info
  75. 52 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_mpdf/print_pdf_mpdf.module
  76. 65 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_mpdf/print_pdf_mpdf.pages.inc
  77. 12 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/INSTALL.txt
  78. 63 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.admin.inc
  79. 6 1
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.class.inc
  80. 32 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.drush.inc
  81. 14 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.info
  82. 17 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.install
  83. 118 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.module
  84. 285 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.pages.inc
  85. 17 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/INSTALL.txt
  86. 47 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.admin.inc
  87. 53 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.drush.inc
  88. 13 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.info
  89. 15 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.install
  90. 106 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.module
  91. 85 0
      sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.pages.inc
  92. 68 240
      sites/all/modules/contrib/admin/print/print_pdf/print_pdf.admin.inc
  93. 144 0
      sites/all/modules/contrib/admin/print/print_pdf/print_pdf.api.php
  94. 23 176
      sites/all/modules/contrib/admin/print/print_pdf/print_pdf.drush.inc
  95. 5 10
      sites/all/modules/contrib/admin/print/print_pdf/print_pdf.info
  96. 106 22
      sites/all/modules/contrib/admin/print/print_pdf/print_pdf.install
  97. 349 479
      sites/all/modules/contrib/admin/print/print_pdf/print_pdf.module
  98. 80 530
      sites/all/modules/contrib/admin/print/print_pdf/print_pdf.pages.inc
  99. 29 1
      sites/all/modules/contrib/admin/print/print_pdf/print_pdf.views.inc
  100. 2 7
      sites/all/modules/contrib/admin/print/print_ui/css/print_ui.theme-rtl.css

+ 1 - 1
sites/all/modules/contrib/admin/context/README.txt

@@ -13,7 +13,7 @@ version. You will need the latest CTools (as of Sept. 16 2010) from here:
 - all reactions
 - context UI
 - context layouts
-- inline editor (with Admin 2.x for D7)
+- inline editor (see the context_ui README file for info on enabling)
 
 ### Expect API changes
 

+ 11 - 0
sites/all/modules/contrib/admin/context/context.api.php

@@ -128,3 +128,14 @@ function hook_context_load_alter(&$context) {
     );
   }
 }
+
+/**
+ * Allows for finer grained access mechanisms to using the json
+ * rendering capabilities of the block reaction when a user isn't
+ * granted the administer contexts or context ajax block access
+ * permission
+ * @param $block_id
+ *   ID of block in module-delta format
+ */
+function hook_context_allow_ajax_block_access($block_id) {
+}

+ 29 - 12
sites/all/modules/contrib/admin/context/context.core.inc

@@ -57,6 +57,11 @@ function context_theme() {
     'path' => drupal_get_path('module', 'context') . '/theme',
     'file' => 'context_reaction_block.theme.inc',
   );
+  $items['context_block_edit_wrap'] = array(
+    'render element' => 'element',
+    'path' => drupal_get_path('module', 'context') . '/theme',
+    'file' => 'context_reaction_block.theme.inc',
+  );
   return $items;
 }
 
@@ -105,7 +110,8 @@ function context_ctools_render_alter($info, $page, $data) {
 function context_entity_prepare_view($prepare, $entity_type) {
   if ($entity_type === 'taxonomy_term' && count($prepare) === 1) {
     $term = reset($prepare);
-    if ($term === menu_get_object('taxonomy_term', 2) && $plugin = context_get_plugin('condition', 'taxonomy_term')) {
+    $menu = menu_get_object('taxonomy_term', 2);
+    if ($menu && $term->tid == $menu->tid && $plugin = context_get_plugin('condition', 'taxonomy_term')) {
       $plugin->execute($term, 'view');
     }
   }
@@ -115,11 +121,9 @@ function context_entity_prepare_view($prepare, $entity_type) {
  * Implementation of hook_node_view().
  */
 function context_node_view($node, $view_mode) {
-  if ($view_mode === 'full') {
-    $object = menu_get_object();
-    if (isset($object->nid) && $object->nid === $node->nid) {
-      context_node_condition($node, 'view');
-    }
+  $object = menu_get_object();
+  if (isset($object->nid) && $object->nid === $node->nid) {
+    context_node_condition($node, 'view');
   }
 }
 
@@ -315,21 +319,21 @@ function context_context_page_condition() {
   if ($plugin = context_get_plugin('condition', 'menu')) {
     $plugin->execute();
   }
-  if ($plugin = context_get_plugin('condition', 'sitewide')) {
+  if ($plugin = context_get_plugin('condition', 'default')) {
     $plugin->execute(1);
   }
   if ($plugin = context_get_plugin('condition', 'context')) {
     $plugin->execute();
   }
+  if ($plugin = context_get_plugin('condition', 'context_all')) {
+    $plugin->execute();
+  }
 }
 
 /**
  * Implementation of hook_context_page_reaction().
  */
 function context_context_page_reaction() {
-  if ($plugin = context_get_plugin('reaction', 'breadcrumb')) {
-    $plugin->execute();
-  }
   if ($plugin = context_get_plugin('reaction', 'css_injector')) {
     $plugin->execute();
   }
@@ -342,10 +346,10 @@ function context_context_page_reaction() {
  * Implementation of hook_preprocess_page().
  */
 function context_preprocess_page(&$vars) {
-  if ($plugin = context_get_plugin('reaction', 'menu')) {
+  if ($plugin = context_get_plugin('reaction', 'theme')) {
     $plugin->execute($vars);
   }
-  if ($plugin = context_get_plugin('reaction', 'theme')) {
+  if ($plugin = context_get_plugin('reaction', 'template_suggestions')) {
     $plugin->execute($vars);
   }
   /*
@@ -358,6 +362,19 @@ function context_preprocess_page(&$vars) {
   */
 }
 
+/**
+* Implementation of hook_delivery_callback_alter().
+* Based on menu_position's and menu_trail_by_path's implementations.
+*/
+function context_page_delivery_callback_alter() {
+  if ($plugin = context_get_plugin('reaction', 'menu')) {
+    $plugin->execute();
+  }
+  if ($plugin = context_get_plugin('reaction', 'breadcrumb')) {
+    $plugin->execute();
+  }
+}
+
 /**
  * Implementation of hook_preprocess_html().
  */

+ 3 - 3
sites/all/modules/contrib/admin/context/context.info

@@ -8,9 +8,9 @@ files[] = tests/context.test
 files[] = tests/context.conditions.test
 files[] = tests/context.reactions.test
 
-; Information added by drupal.org packaging script on 2013-07-29
-version = "7.x-3.0-beta7"
+; Information added by Drupal.org packaging script on 2015-01-06
+version = "7.x-3.6"
 core = "7.x"
 project = "context"
-datestamp = "1375065368"
+datestamp = "1420573188"
 

+ 1 - 0
sites/all/modules/contrib/admin/context/context.install

@@ -1,5 +1,6 @@
 <?php
 
+
 /**
  * Implementation of hook_install().
  */

+ 7 - 1
sites/all/modules/contrib/admin/context/context.module

@@ -165,9 +165,15 @@ function context_context_registry() {
  * Implementation of hook_init().
  */
 function context_init() {
+  if ($plugin = context_get_plugin('condition', 'sitewide')) {
+    $plugin->execute(1);
+  }
   if ($plugin = context_get_plugin('condition', 'path')) {
     $plugin->execute();
   }
+  if ($plugin = context_get_plugin('condition', 'query_string')) {
+    $plugin->execute();
+  }
   if ($plugin = context_get_plugin('condition', 'language')) {
     global $language;
     $plugin->execute($language->language);
@@ -458,7 +464,7 @@ function context_empty($element) {
     }
   }
   else {
-    $empty = $empty && empty($element);
+    $empty = $empty && !isset($element);
   }
   return $empty;
 }

+ 54 - 2
sites/all/modules/contrib/admin/context/context.plugins.inc

@@ -7,10 +7,15 @@ function _context_context_registry() {
   $registry = array();
   $registry['conditions'] = array(
     'context' => array(
-      'title' => t('Context'),
-      'description' => t('Set this context on the basis of other active contexts. Put each context on a separate line. You can use the <code>*</code> character (asterisk) as a wildcard and the <code>~</code> character (tilde) to prevent this context from activating if the listed context is active. Other contexts which use context conditions can not be used to exclude this context from activating.'),
+      'title' => t('Context (any)'),
+      'description' => t('Set this context on the basis of other active contexts. Put each context on a separate line. The condition will pass if <em>any</em> of the contexts are active. You can use the <code>*</code> character (asterisk) as a wildcard and the <code>~</code> character (tilde) to prevent this context from activating if the listed context is active. Other contexts which use context conditions can not be used to exclude this context from activating.'),
       'plugin' => 'context_condition_context',
     ),
+    'context_all' => array(
+      'title' => t('Context (all)'),
+      'description' => t('Set this context on the basis of other active contexts. Put each context on a separate line. The condition will pass only if <em>all</em> of the contexts are active. You can use the <code>*</code> character (asterisk) as a wildcard and the <code>~</code> character (tilde) to prevent this context from activating if the listed context is active. Other contexts which use context conditions can not be used to exclude this context from activating.'),
+      'plugin' => 'context_condition_context_all',
+    ),
     'node' => array(
       'title' => t('Node type'),
       'description' => t('Set this context when viewing a node page or using the add/edit form of one of these content types.'),
@@ -21,11 +26,21 @@ function _context_context_registry() {
       'description' => t('Should this context always be set? If <strong>true</strong>, this context will be active across your entire site.'),
       'plugin' => 'context_condition_sitewide',
     ),
+    'default' => array(
+      'title' => t('Default context'),
+      'description' => t('This context will be set if no other context is active except sitewide contexts.'),
+      'plugin' => 'context_condition_default',
+    ),
     'path' => array(
       'title' => t('Path'),
       'description' => t('Set this context when any of the paths above match the page path. Put each path on a separate line. You can use the <code>*</code> character (asterisk) as a wildcard and the <code>~</code> character (tilde) to exclude one or more paths. Use &lt;front&gt; for the site front page.'),
       'plugin' => 'context_condition_path',
     ),
+    'query_string' => array(
+      'title' => t('Query String'),
+      'description' => t('Set this context when any of the query strings above match the page query string. Put each query string on a separate line. You can use the "*" character as a wildcard and <code>~</code> to exclude one or more query strings.'),
+      'plugin' => 'context_condition_query_string',
+    ),
     'user' => array(
       'title' => t('User role'),
       'description' => t('Set this context when the current user has one of the selected role(s).'),
@@ -98,6 +113,11 @@ function _context_context_registry() {
       'description' => t('Set the breadcrumb trail to the selected menu item.'),
       'plugin' => 'context_reaction_breadcrumb',
     ),
+    'template_suggestions' => array(
+      'title' => t('Template suggestions'),
+      'description' => t('Add template suggestions using context.'),
+      'plugin' => 'context_reaction_template_suggestions',
+    ),
     'theme' => array(
       'title' => t('Theme Page'),
       'description' => t('Control page theme variables using context.'),
@@ -155,6 +175,14 @@ function _context_context_plugins() {
       'parent' => 'context_condition_path',
     ),
   );
+  $plugins['context_condition_context_all'] = array(
+    'handler' => array(
+      'path' => drupal_get_path('module', 'context') . '/plugins',
+      'file' => 'context_condition_context_all.inc',
+      'class' => 'context_condition_context_all',
+      'parent' => 'context_condition_path',
+    ),
+  );
   $plugins['context_condition_node'] = array(
     'handler' => array(
       'path' => drupal_get_path('module', 'context') . '/plugins',
@@ -171,6 +199,14 @@ function _context_context_plugins() {
       'parent' => 'context_condition',
     ),
   );
+  $plugins['context_condition_default'] = array(
+    'handler' => array(
+      'path' => drupal_get_path('module', 'context') . '/plugins',
+      'file' => 'context_condition_default.inc',
+      'class' => 'context_condition_default',
+      'parent' => 'context_condition',
+    ),
+  );
   $plugins['context_condition_path'] = array(
     'handler' => array(
       'path' => drupal_get_path('module', 'context') . '/plugins',
@@ -179,6 +215,14 @@ function _context_context_plugins() {
       'parent' => 'context_condition',
     ),
   );
+  $plugins['context_condition_query_string'] = array(
+    'handler' => array(
+      'path' => drupal_get_path('module', 'context') .'/plugins',
+      'file' => 'context_condition_query_string.inc',
+      'class' => 'context_condition_query_string',
+      'parent' => 'context_condition_path',
+    ),
+  );
   $plugins['context_condition_user'] = array(
     'handler' => array(
       'path' => drupal_get_path('module', 'context') . '/plugins',
@@ -294,6 +338,14 @@ function _context_context_plugins() {
       'parent' => 'context_reaction_menu',
     ),
   );
+  $plugins['context_reaction_template_suggestions'] = array(
+    'handler' => array(
+      'path' => drupal_get_path('module', 'context') . '/plugins',
+      'file' => 'context_reaction_template_suggestions.inc',
+      'class' => 'context_reaction_template_suggestions',
+      'parent' => 'context_reaction',
+    ),
+  );
   $plugins['context_reaction_menu'] = array(
     'handler' => array(
       'path' => drupal_get_path('module', 'context') . '/plugins',

+ 3 - 3
sites/all/modules/contrib/admin/context/context_layouts/context_layouts.info

@@ -6,9 +6,9 @@ core = 7.x
 
 files[] = plugins/context_layouts_reaction_block.inc
 
-; Information added by drupal.org packaging script on 2013-07-29
-version = "7.x-3.0-beta7"
+; Information added by Drupal.org packaging script on 2015-01-06
+version = "7.x-3.6"
 core = "7.x"
 project = "context"
-datestamp = "1375065368"
+datestamp = "1420573188"
 

+ 3 - 1
sites/all/modules/contrib/admin/context/context_layouts/context_layouts.module

@@ -49,7 +49,7 @@ function context_layouts_theme() {
         if (!empty($layout['template'])) {
           $info["page__context_layouts_{$theme->name}_{$layout['layout']}"] = array(
             'template' => $layout['template'],
-            'path' => drupal_get_path('theme', $theme->name),
+            'path' => $layout['path'],
           );
         }
       }
@@ -107,10 +107,12 @@ function context_layouts_get_layouts($theme = NULL, $reset = FALSE) {
 
     // Merge layout info into a single array.
     foreach ($themes as $key => $info) {
+      $path = drupal_get_path('theme', $key);
       if (!empty($info['layouts'])) {
         foreach ($info['layouts'] as $layout => $layout_info) {
           $layout_info['layout'] = str_replace('-', '_', $layout);
           $layout_info['theme'] = $key;
+          $layout_info['path'] = $path;
           $layouts[$theme][$layout] = $layout_info;
         }
       }

+ 3 - 3
sites/all/modules/contrib/admin/context/context_ui/context_ui.info

@@ -8,9 +8,9 @@ configure = admin/structure/context
 files[] = context.module
 files[] = tests/context_ui.test
 
-; Information added by drupal.org packaging script on 2013-07-29
-version = "7.x-3.0-beta7"
+; Information added by Drupal.org packaging script on 2015-01-06
+version = "7.x-3.6"
 core = "7.x"
 project = "context"
-datestamp = "1375065368"
+datestamp = "1420573188"
 

+ 12 - 4
sites/all/modules/contrib/admin/context/context_ui/context_ui.module

@@ -80,6 +80,10 @@ function context_ui_permission() {
     'title' => 'Administer contexts',
     'description' => 'Associate menus, views, blocks, etc. with different contexts to structure your site.'
   );
+  $permissions['context ajax block access'] = array(
+    'title' => t('Access All Blocks'),
+    'description' => t('Allows users to access all rendered blocks via an AJAX callback. If you have some blocks that should not be rendered for some users but need those users to be able to use context UI, then implement hook_context_allow_ajax_block_access with the necessary logic.'),
+  );
   return $permissions;
 }
 
@@ -383,8 +387,10 @@ function context_ui_menu_contextual_links_alter(&$links, $router_item, $root_pat
  * A page call back to activate the context_ui inline editor dialog.
  */
 function context_ui_activate() {
-  $_SESSION['context_ui_active'] = $_GET['destination'];
-  drupal_goto($_GET['destination']);
+  if (isset($_GET['destination']) && !url_is_external($_GET['destination'])) {
+    $_SESSION['context_ui_active'] = $_GET['destination'];
+    drupal_goto($_GET['destination']);
+  }
 }
 
 /**
@@ -394,8 +400,10 @@ function context_ui_activate() {
  * to navigate to when deactivating context_ui_editor
  */
 function context_ui_deactivate() {
-  $_SESSION['context_ui_active'] = FALSE;
-  drupal_goto($_GET['destination']);
+  if (isset($_GET['destination']) && !url_is_external($_GET['destination'])) {
+    $_SESSION['context_ui_active'] = FALSE;
+    drupal_goto($_GET['destination']);
+  }
 }
 
 /**

+ 1 - 0
sites/all/modules/contrib/admin/context/context_ui/export_ui/context_export_ui.class.php

@@ -73,6 +73,7 @@ class context_export_ui extends ctools_export_ui {
     if (!empty($this->plugin['form']['submit'])) {
       $this->plugin['form']['submit']($form, $form_state);
     }
+    context_invalidate_cache();
   }
 
   /**

+ 1 - 0
sites/all/modules/contrib/admin/context/context_ui/tests/context_ui.test

@@ -24,6 +24,7 @@ class ContextUiTestCase extends DrupalWebTestCase {
     $admin_user = $this->drupalCreateUser(array(
       'access administration pages',
       'administer site configuration',
+      'administer contexts',
       'access content',
       'create blog content'
     ));

+ 43 - 1
sites/all/modules/contrib/admin/context/plugins/context_condition_context.inc

@@ -9,7 +9,8 @@ class context_condition_context extends context_condition_path {
       $active_contexts = array_keys(context_active_contexts());
       foreach ($this->get_contexts() as $context) {
         if (!in_array($context->name, $active_contexts, TRUE) && $values = $this->fetch_from_context($context, 'values')) {
-          if ($this->match($active_contexts, $values)) {
+          // Always check against the active contexts.
+          if ($this->match(array_keys(context_active_contexts()), $values)) {
             $this->condition_met($context);
           }
         }
@@ -20,4 +21,45 @@ class context_condition_context extends context_condition_path {
       }
     }
   }
+
+  /**
+   * Retrieve all context conditions.
+   *
+   * This method is slightly adapted to context_condition::get_contexts() in
+   * order to ensure that a context that is used as condition in another context
+   * gets handled before.
+   */
+  function get_contexts($value = NULL) {
+    $map = context_condition_map();
+    $map = isset($map[$this->plugin]) ? $map[$this->plugin] : array();
+
+    $contexts = array();
+
+    // Add the contexts that are needed for conditions in the other contexts
+    // first. Start with the negated ones first, as we can not unset a met
+    // condition afterwards.
+    krsort($map);
+    foreach ($map as $key => $submap) {
+      // Negated context conditions start with a "~".
+      if (substr($key, 0, 1) == "~") {
+        $key = substr($key, 1);
+      }
+      if (!isset($contexts[$key])) {
+        $context = context_load($key);
+        // Check if context exists. This will fail for wildcards.
+        if ($context) {
+          $contexts[$context->name] = $context;
+        }
+      }
+    }
+    foreach ($map as $key => $submap) {
+      foreach ($submap as $name) {
+        if (!isset($contexts[$name])) {
+          $context = context_load($name);
+          $contexts[$context->name] = $context;
+        }
+      }
+    }
+    return $contexts;
+  }
 }

+ 29 - 0
sites/all/modules/contrib/admin/context/plugins/context_condition_context_all.inc

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * Expose active contexts as a context condition.
+ */
+class context_condition_context_all extends context_condition_path {
+  function execute() {
+    if ($this->condition_used()) {
+      $active_contexts = array_keys(context_active_contexts());
+      foreach ($this->get_contexts() as $context) {
+
+        // Only test contexts that haven't been activated yet,
+        // and have values set.
+        if (!in_array($context->name, $active_contexts, TRUE) && $values = $this->fetch_from_context($context, 'values')) {
+
+          // The condition is met if all contexts are active.
+          if (count(array_intersect($values, $active_contexts)) == count($values)) {
+            $this->condition_met($context);
+          }
+        }
+      }
+
+      // If the list of active contexts has changed, we need to recurse.
+      if ($active_contexts != array_keys(context_active_contexts())) {
+        $this->execute();
+      }
+    }
+  }
+}

+ 35 - 0
sites/all/modules/contrib/admin/context/plugins/context_condition_default.inc

@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * Simple condition that sets context active if no other non-default and non
+ * sitewide context is active.
+ */
+class context_condition_default extends context_condition {
+  function condition_values() {
+    return array('context_condition_default' => t('Default context'));
+  }
+
+  function editor_form($context = NULL) {
+    $form = parent::editor_form($context);
+    $form[1]['#title'] = t('Default context');
+    $form['#weight'] = -10;
+    return $form;
+  }
+
+  function execute() {
+    if ($this->condition_used()) {
+      $active_contexts = context_active_contexts();
+
+      foreach ($active_contexts as $name => $context) {
+        foreach (array_keys($context->conditions) as $cond) {
+          if (!in_array($cond, array('default', 'sitewide'))) {
+            return;
+          }
+        }
+      }
+      foreach ($this->get_contexts('context_condition_default') as $context) {
+        $this->condition_met($context, 'context_condition_default');
+      }
+    }
+  }
+}

+ 28 - 0
sites/all/modules/contrib/admin/context/plugins/context_condition_query_string.inc

@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file context_condition_query_string.inc
+ *
+ * Similar to context_condition_path but for entire query string.
+ */
+
+/**
+ * Expose query strings as a context condition.
+ */
+class context_condition_query_string extends context_condition_path {
+
+  /**
+   * Execute.
+   */
+  function execute() {
+    if ($this->condition_used()) {
+      $current_query_string = $_SERVER["QUERY_STRING"];
+      foreach ($this->get_contexts() as $context) {
+        $query_strings = $this->fetch_from_context($context, 'values');
+        if ($this->match($current_query_string, $query_strings, TRUE)) {
+          $this->condition_met($context);
+        }
+      }
+    }
+  }
+}

+ 1 - 1
sites/all/modules/contrib/admin/context/plugins/context_reaction_block.css

@@ -168,7 +168,6 @@ body.context-editing  .draggable:hover a.context-block-remove {
  * Block visibility ===================================================
  */
 #context-blockform  .context-blockform-selector {
-  height:20em;
   overflow:auto;
   }
 
@@ -179,6 +178,7 @@ body.context-editing  .draggable:hover a.context-block-remove {
   border:1px solid #ddd;
   padding:10px;
   width:50%;
+  vertical-align: top;
   }
 
 #context-blockform td.blocks  .label,

+ 75 - 67
sites/all/modules/contrib/admin/context/plugins/context_reaction_block.inc

@@ -42,13 +42,19 @@ class context_reaction_block extends context_reaction {
       $group = isset($block->context_group) ? $block->context_group : $block->module;
       if (!isset($form['selector'][$group])) {
         $form['selector'][$group] = array(
-          '#type' => 'checkboxes',
+          '#type' => 'fieldset',
+          '#collapsible' => TRUE, 
+          '#collapsed' => TRUE,
           '#title' => isset($block->context_group) ? $block->context_group : $modules[$block->module],
+        );
+        $form['selector'][$group]['checkboxes'] = array(
+          '#type' => 'checkboxes',
           '#options' => array(),
         );
       }
-      $form['selector'][$group]['#options'][$block->bid] = check_plain($block->info);
+      $form['selector'][$group]['checkboxes']['#options'][$block->bid] = check_plain($block->info);
     }
+
     ksort($form['selector']);
 
     /**
@@ -58,7 +64,7 @@ class context_reaction_block extends context_reaction {
       '#tree' => TRUE,
       '#theme' => 'context_block_regions_form',
     );
-    foreach (system_region_list($theme_key, REGIONS_VISIBLE) as $region => $label) {
+    foreach ($this->system_region_list($theme_key, REGIONS_VISIBLE) as $region => $label) {
       $form['blocks'][$region] = array(
         '#type' => 'item',
         '#title' => $label,
@@ -215,7 +221,7 @@ class context_reaction_block extends context_reaction {
     }
 
     // Populate all block regions
-    $all_regions = system_region_list($theme);
+    $all_regions = $this->system_region_list($theme);
 
     // Load all region content assigned via blocks.
     foreach (array_keys($all_regions) as $region) {
@@ -255,7 +261,7 @@ class context_reaction_block extends context_reaction {
    */
   protected function is_enabled_region($region) {
     global $theme;
-    $regions = array_keys(system_region_list($theme));
+    $regions = array_keys($this->system_region_list($theme));
     return in_array($region, $regions, TRUE);
   }
 
@@ -290,7 +296,7 @@ class context_reaction_block extends context_reaction {
       return FALSE;
     }
     // Check that this region is not hidden
-    $visible = system_region_list($theme, REGIONS_VISIBLE);
+    $visible = $this->system_region_list($theme, REGIONS_VISIBLE);
     return $requirements && $this->is_enabled_region($region) && isset($visible[$region]);
   }
 
@@ -299,15 +305,7 @@ class context_reaction_block extends context_reaction {
    */
   protected function editable_block($block) {
     if (!empty($block->content)) {
-      $block->content = array(
-        'content' => $block->content,
-        'context' => array('#markup' => "<a id='context-block-{$block->module}-{$block->delta}' class='context-block editable edit-{$block->context}'></a>"),
-      );
-      //Contextual links are in the wrong spot in the render array once we've nested them
-      if (isset($block->content['content']['#contextual_links'])) {
-        $block->content['#contextual_links'] = $block->content['content']['#contextual_links'];
-        unset($block->content['content']['#contextual_links']);
-      }
+      $block->content['#theme_wrappers'][] = 'context_block_edit_wrap';
     }
     else {
       // the block alter in context.module should ensure that blocks are never
@@ -328,7 +326,7 @@ class context_reaction_block extends context_reaction {
          context_isset('context_ui', 'context_ui_editor_present'))
     ) {
       global $theme;
-      $regions = system_region_list($theme);
+      $regions = $this->system_region_list($theme);
       $name = isset($regions[$region]) ? $regions[$region] : $region;
       // The negative weight + sorted will push our region marker to the top of the region
       $build['context'] = array(
@@ -388,13 +386,29 @@ class context_reaction_block extends context_reaction {
       }
       
       $this->is_editable_check($context_blocks);
-      foreach ($context_blocks as $r => $blocks) {
-        $context_blocks[$r] = _block_render_blocks($blocks);
+      global $theme;
+      $active_regions = $this->system_region_list($theme);
+
+      // Make context renders regions in the same order as core.
+      $_context_blocks = array();
+      foreach ($active_regions as $r => $name) {
+        if (isset($context_blocks[$r])) {
+          $_context_blocks[$r] = $context_blocks[$r];
+        }
+      }
+      $context_blocks = $_context_blocks;
+      unset($_context_blocks);
 
-        // Make blocks editable if allowed.
-        if ($this->is_editable_region($r)) {
-          foreach ($context_blocks[$r] as $key => $block) {
-            $context_blocks[$r][$key] = $this->editable_block($block);
+      foreach ($context_blocks as $r => $blocks) {
+        //only render blocks in an active region
+        if (array_key_exists($r, $active_regions)) {
+          $context_blocks[$r] = _block_render_blocks($blocks);
+
+          // Make blocks editable if allowed.
+          if ($this->is_editable_region($r)) {
+            foreach ($context_blocks[$r] as $key => $block) {
+              $context_blocks[$r][$key] = $this->editable_block($block);
+            }
           }
         }
 
@@ -514,7 +528,12 @@ class context_reaction_block extends context_reaction {
         $result = db_select('block')
           ->fields('block')
           ->condition('theme', $theme_key)
-          ->execute();
+          ->execute()
+          ->fetchAllAssoc('bid');
+
+        drupal_alter('block_list', $result);
+        drupal_alter('context_block_list', $result);
+
         foreach ($result as $row) {
           if (isset($block_info["{$row->module}-{$row->delta}"])) {
             $block_info["{$row->module}-{$row->delta}"] = (object) array_merge((array) $row, (array) $block_info["{$row->module}-{$row->delta}"]);
@@ -576,50 +595,9 @@ class context_reaction_block extends context_reaction {
     if (function_exists('json_decode')) {
       return json_decode($json, $assoc);
     }
-    return context_reaction_block::_json_decode($json);
-  }
-
-  /**
-   * From http://www.php.net/manual/en/function.json-decode.php#91216
-   * with modifications for consistency with output of json_decode().
-   *
-   * Original author: walidator.info 2009.
-   */
-  static function _json_decode($json) {
-    $comment = FALSE;
-    $out = '$x = ';
-    for ($i=0; $i < strlen($json); $i++) {
-      if (!$comment) {
-        switch ($json[$i]) {
-          case '{':
-            $out .= ' (object) array(';
-            break;
-          case '}':
-            $out .= ')';
-            break;
-          case '[':
-            $out .= ' array(';
-            break;
-          case ']':
-            $out .= ')';
-            break;
-          case ':';
-            $out .= '=>';
-            break;
-          default:
-            $out .= $json[$i];
-            break;
-        }
-      }
-      else {
-        $out .= $json[$i];
-      }
-      if ($json[$i] == '"') {
-        $comment = !$comment;
-      }
+    else {
+      watchdog('context', 'Please upgrade your PHP version to one that supports json_decode.');
     }
-    eval($out . ';');
-    return $x;
   }
 
   /**
@@ -640,7 +618,7 @@ class context_reaction_block extends context_reaction {
       list($bid, $context) = explode(',', $param);
       list($module, $delta) = explode('-', $bid, 2);
       // Check token to make sure user has access to block.
-      if (empty($_GET['context_token']) || $_GET['context_token'] != drupal_get_token($bid)) {
+      if (!(user_access('administer contexts') || user_access('context ajax block access') || $this->context_block_ajax_rendering_allowed($bid))) {
         echo drupal_json_encode(array('status' => 0));
         exit;
       }
@@ -670,4 +648,34 @@ class context_reaction_block extends context_reaction {
     echo drupal_json_encode(array('status' => 0));
     drupal_exit();
   }
+
+  /**
+   * Provide caching for system_region_list since it can get called
+   * frequently. Evaluate for removal once https://drupal.org/node/1873450
+   * lands or system_region_list is otherwise cached in core
+   */
+  protected function system_region_list($theme_key, $show = REGIONS_ALL) {
+    static $cache = array();
+    if (!isset($cache[$theme_key])) {
+      $cache[$theme_key] = array();
+    }
+    if (!isset($cache[$theme_key][$show])) {
+      $cache[$theme_key][$show] = system_region_list($theme_key, $show);
+    }
+    return $cache[$theme_key][$show];
+  }
+
+  /**
+   * Allow modules to selectively allow ajax rendering of a specific block
+   */
+  private function context_block_ajax_rendering_allowed($bid) {
+    $allowed = FALSE;
+    foreach (module_invoke_all('context_allow_ajax_block_access', $bid) as $module_allow) {
+      $allowed = $allow || $module_allow;
+      if ($allowed) {
+        break;
+      }
+    }
+    return $allowed;
+  }
 }

+ 1 - 6
sites/all/modules/contrib/admin/context/plugins/context_reaction_block.js

@@ -327,11 +327,6 @@ DrupalContextBlockEditor.prototype = {
       // Construct query params for our AJAX block request.
       var params = Drupal.settings.contextBlockEditor.params;
       params.context_block = bid + ',' + context;
-      if (!Drupal.settings.contextBlockEditor.block_tokens || !Drupal.settings.contextBlockEditor.block_tokens[bid]) {
-        alert(Drupal.t('An error occurred trying to retrieve block content. Please contact a site administer.'));
-        return;
-     }
-     params.context_token = Drupal.settings.contextBlockEditor.block_tokens[bid];
 
       // Replace item with loading block.
       //ui.sender.append(ui.item);
@@ -443,7 +438,7 @@ DrupalContextBlockEditor.prototype = {
         dropOnEmpty: true,
         placeholder: 'draggable-placeholder',
         forcePlaceholderSize: true,
-        items: '> .block:has(a.context-block.editable)',
+        items: '> *:has(a.context-block.editable)',
         handle: 'a.context-block-handle',
         start: function(event, ui) { self.scriptFix(event, ui, editor, context); },
         stop: function(event, ui) { self.addBlock(event, ui, editor, context); },

+ 26 - 26
sites/all/modules/contrib/admin/context/plugins/context_reaction_breadcrumb.inc

@@ -5,35 +5,35 @@
  */
 class context_reaction_breadcrumb extends context_reaction_menu {
   /**
-   * Override of execute().
+   * Overrides set_active_trail_from_link to set the breadcrumb instead of the menu path.
    */
-  function execute(&$vars = NULL) {
-    if ($active_paths = $this->get_active_paths()) {
-      $breadcrumb = array(l(t('Home'), '<front>', array('purl' => array('disabled' => TRUE))));
-      foreach ($active_paths as $path) {
-        $result = db_select('menu_links')
-          ->fields('menu_links', array('p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8'))
-          ->condition('hidden', 0)
-          ->condition('link_path', $path)
-          ->execute();
-        while ($parents = $result->fetchAssoc()) {
-          $set = FALSE;
-          foreach (array_filter($parents) as $plid) {
-            $parent = menu_link_load($plid);
-            if ($parent && $parent['access'] && empty($parent['hidden']) && !empty($parent['title'])) {
-              $set = TRUE;
-              $breadcrumb[] = l($parent['title'], $parent['href']);
-            }
-          }
-          // Only set the breadcrumb if one or more links were added to the
-          // trail. If not, continue iterating through possible menu links.
-          if ($set) {
-            drupal_set_breadcrumb($breadcrumb);
-            break;
-          }
+  function set_active_trail_from_link($item) {
+    $result = db_select('menu_links')
+      ->fields('menu_links', array('p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8'))
+      ->condition('hidden', 0)
+      ->condition('link_path', $item['link_path'])
+      ->execute();
+    while ($parents = $result->fetchAssoc()) {
+      $set = FALSE;
+      foreach (array_filter($parents) as $plid) {
+        $parent = menu_link_load($plid);
+        if ($parent && $parent['access'] && empty($parent['hidden']) && !empty($parent['title'])) {
+          $set = TRUE;
+          $breadcrumb[] = l($parent['title'], $parent['href']);
         }
       }
+      // Only set the breadcrumb if one or more links were added to the
+      // trail. If not, continue iterating through possible menu links.
+      if ($set) {
+        drupal_set_breadcrumb($breadcrumb);
+        break;
+      }
     }
   }
+  /**
+   * Return the title to be used for the current menu item.
+   */
+  function get_link_title($item) {
+    return module_exists('i18n_menu') ? _i18n_menu_link_title($item) : $item['title'];
+  }
 }
-

+ 15 - 1
sites/all/modules/contrib/admin/context/plugins/context_reaction_debug.inc

@@ -12,13 +12,27 @@ class context_reaction_debug extends context_reaction {
     return array('debug' => 1);
   }
 
+  /**
+   * Settings form for variables.
+   */
+  function settings_form() {
+    $form = array();
+    $form['context_reaction_debug_enable_global'] = array(
+      '#title' => t('Enable debug reaction on all contexts'),
+      '#type' => 'checkbox',
+      '#default_value' => variable_get('context_reaction_debug_enable_global', FALSE),
+      '#description' => t('Enable the debug reaction on all contexts.')
+    );
+    return $form;
+  }
+
   /**
    * Output a list of active contexts.
    */
   function execute() {
     $contexts = context_active_contexts();
     foreach ($contexts as $context) {
-      if (!empty($context->reactions['debug'])) {
+      if (!empty($context->reactions['debug']) || variable_get('context_reaction_debug_enable_global', FALSE)) {
         if (user_access('administer site configuration') && module_exists('context_ui')) {
           $name = l($context->name, "admin/structure/context/list/{$context->name}", array('query' => array('destination' => $_GET['q'])));
         }

+ 85 - 84
sites/all/modules/contrib/admin/context/plugins/context_reaction_menu.inc

@@ -8,35 +8,33 @@ class context_reaction_menu extends context_reaction {
    * Provide a form element that allow the admin to chose a menu item.
    */
   function options_form($context) {
+    $options = array("-- " . t('None') . " --");
     if (module_exists('menu')) {
       $menus = menu_parent_options(menu_get_menus(), array('mlid' => 0));
-      $root_menus = array();
-      foreach ($menus as $key => $name) {
-        $id = explode(':', $key);
-        if ($id[1] == '0') {
-          $root_menus[$id[0]] = check_plain($name);
+      $menu_names = array();
+      foreach ($menus as $id => $title) {
+        list($menu_name, $mlid) = explode(':', $id);
+        // Store the title each menu for reference.
+        if ($mlid == '0') {
+          $menu_names[$menu_name] = $title;
         }
         else {
-          $link = menu_link_load($id[1]);
+          $link = menu_link_load($mlid);
           $identifier = $link['link_path'];
-          $root_menu = $root_menus[$id[0]];
-          while (isset($menus[$root_menu][$identifier])) {
+          $root_menu = $menu_names[$menu_name];
+          while (isset($options[$root_menu][$identifier])) {
             $identifier .= "'";
           }
-          $menus[$root_menu][$identifier] = $name;
+          $options[$root_menu][$menu_name . ':' . $identifier] = $title;
         }
-        unset($menus[$key]);
       }
-      array_unshift($menus, "-- " . t('None') . " --");
-    }
-    else {
-      $menus = array();
     }
     return array(
       '#title' => $this->title,
       '#description' => $this->description,
-      '#options' => $menus,
+      '#options' => $options,
       '#type' => 'select',
+      '#multiple' => TRUE,
       '#default_value' => $this->fetch_from_context($context),
     );
   }
@@ -46,97 +44,100 @@ class context_reaction_menu extends context_reaction {
    * Trim any identifier padding for non-unique path menu items.
    */
   function options_form_submit($values) {
-    return trim($values, "'");
+    $trimmed = array();
+    foreach ($values as $value) {
+      $value = trim($value, "'");
+      $trimmed[] = $value;
+    }
+    return $trimmed;
   }
 
   /**
-   * If primary + secondary links are pointed at the same menu, provide
-   * contextual trailing by default.
+   * Overrides parent function to include legacy handling for old format of just storing a single path.
    */
-  function execute(&$vars = NULL) {
-    if (variable_get('menu_main_links_source', 'main-menu') == variable_get('menu_secondary_links_source', 'user-menu')) {
-      $vars['main_menu'] = theme_get_setting('toggle_main_menu') ? $this->menu_navigation_links(variable_get('menu_main_links_source', 'main-menu')) : $vars['main_menu'];
-      $vars['secondary_menu'] = theme_get_setting('toggle_secondary_menu') ? $this->menu_navigation_links(variable_get('menu_secondary_links_source', 'secondary-links'), 1) : $vars['secondary_menu'];
-    }
-
-    $vars['main_menu'] = $this->menu_set_active($vars['main_menu']);
-    $vars['secondary_menu'] = $this->menu_set_active($vars['secondary_menu']);
-  }
-
-  function get_active_paths() {
-    $active_paths = array();
-    foreach ($this->get_contexts() as $context) {
-      if (isset($context->reactions[$this->plugin])) {
-        $active_paths[] = $context->reactions[$this->plugin];
+  function fetch_from_context($context) {
+    $values = parent::fetch_from_context($context);
+    // Legacy - convert single string value to an array with a preferred menu
+    if (is_string($values)) {
+      $menu = menu_link_get_preferred($values);
+      if (!$menu) {
+        return array();
       }
+      return array($menu['menu_name'] . ':' . $menu['link_path']);
     }
-    return $active_paths;
+    return $values;
   }
 
   /**
-   * Iterates through a provided links array for use with theme_links()
-   * (e.g. from menu_primary_links()) and provides an active class for
-   * any items that have a path that matches an active context.
-   *
-   * @param $links
-   *   An array of links.
-   * @param $reset
-   *   A boolean flag for resetting the static cache.
-   *
-   * @return
-   *   A modified links array.
+   * Provide active trail in all menus in which our path appears.
    */
-  function menu_set_active($links = array(), $reset = FALSE) {
-    $new_links = array();
-    if (!empty($links)) {
-      $active_paths = $this->get_active_paths();
-
-      // Iterate through the provided links and build a new set of links
-      // that includes active classes
-      foreach ($links as $key => $link) {
-        if (!empty($link['href']) && in_array($link['href'], $active_paths)) {
-          $link['attributes']['class'][] = 'active';
-
-          if (strpos(' active', $key) === FALSE) {
-            $new_links[$key . ' active'] = $link;
+  function execute(&$vars = NULL) {
+    $menu_names = menu_get_active_menu_names();
+    $active_paths = $this->get_active_paths();
+    foreach ($menu_names as $menu_name) {
+      if (isset($active_paths[$menu_name])) {
+        foreach($active_paths[$menu_name] as $path) {
+          if ($link = menu_link_get_preferred($path, $menu_name)) {
+            $this->set_active_trail_from_link($link);
+            return;
           }
         }
-        else {
-          $new_links[$key] = $link;
+      }
+    }
+
+    // None of the links can be found in their preferred menus. Instead we just try to find any of the paths in any
+    // menu. Note that the preferred menu names list is still used but not always honoured.
+    // We hope to not have to fall into this section as we could end up doing rather a lot of lookups.
+    foreach ($active_paths as $menu_name => $paths) {
+      foreach($paths as $path) {
+        if ($link = menu_link_get_preferred($path)) {
+          $this->set_active_trail_from_link($link);
+          return;
         }
       }
     }
-    return $new_links;
   }
 
   /**
-   * Wrapper around menu_navigation_links() that gives themers the option of
-   * building navigation links based on an active context trail.
+   * Helper function to build and set the active trail from a menu link.
+   *
+   * @param $item
+   *   A menu link item.
    */
-  function menu_navigation_links($menu_name, $level = 0) {
-    // Retrieve original path so we can repair it after our hack.
-    $original_path = $_GET['q'];
-    $original_menu_trail = drupal_static('menu_set_active_trail');
-
-    // Retrieve the first active menu path found.
-    if ($active_paths = $this->get_active_paths()) {
-      $path = current($active_paths);
-      if (menu_get_item($path)) {
-        menu_set_active_item($path);
-      }
+  function set_active_trail_from_link($item) {
+    menu_tree_set_path($item['menu_name'], $item['link_path']);
+    $trail = array();
+    while($item) {
+      array_unshift($trail, $item);
+      $item = menu_link_load($item['plid']);
     }
+    array_unshift($trail, array(
+      'title' => t('Home'),
+      'href' => '<front>',
+      'link_path' => '',
+      'localized_options' => array(),
+      'type' => 0,
+    ));
+    menu_set_active_trail($trail);
+  }
 
-    // Build the links requested
-    if (module_exists('i18n_menu')) {
-      $links = i18n_menu_navigation_links($menu_name, $level);
-    } else {
-      $links = menu_navigation_links($menu_name, $level);
+  /**
+   * Helper function to return the list of currently active paths.
+   *
+   * The paths are grouped by menu name.
+   */
+  function get_active_paths() {
+    $active_paths = array();
+    foreach ($this->get_contexts() as $context) {
+      $paths = $this->fetch_from_context($context);
+      $active_paths = array_merge($active_paths, $paths);
     }
 
-    // Repair and get out
-    menu_set_active_item($original_path);
-    $repair_menu_trail = &drupal_static('menu_set_active_trail');
-    $repair_menu_trail = $original_menu_trail;
-    return $links;
+    $by_menu_name = array();
+    foreach ($active_paths as $id) {
+      list($menu_name, $path) = explode(':', $id);
+      $by_menu_name[$menu_name][] = $path;
+    }
+    return $by_menu_name;
   }
 }

+ 47 - 0
sites/all/modules/contrib/admin/context/plugins/context_reaction_template_suggestions.inc

@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * Add template suggestions as a context reaction.
+ */
+class context_reaction_template_suggestions extends context_reaction {
+
+  /**
+   * Display the text area field for adding new template suggestions.
+   */
+  function options_form($context) {
+    $default_value = $this->fetch_from_context($context);
+
+    return array(
+      '#title' => t('Template suggestions'),
+      '#type' => 'textarea',
+      '#description' => t('Enter template suggestions such as "page__front", one per line, in order of preference (using underscores instead of hyphens).  For more information, please visit ') . l(t('Drupal 7 Template (Theme Hook) Suggestions'), 'http://drupal.org/node/1089656', array(array('target' => '_blank'), 'html' => TRUE,)) . '.',
+      '#default_value' => is_string($default_value) ? $default_value : '',
+    );
+  }
+
+  /**
+   * Add any new template suggestions to the current list.
+   */
+  function execute(&$vars = NULL) {
+
+    // Get the list of contexts associated with this reaction.
+    $contexts = $this->get_contexts();
+
+    // Iterate through each, and process those with something set.
+    foreach ($contexts as $context) {
+      if (isset($context->reactions) && (!empty($context->reactions[$this->plugin]))) {
+
+        // Get the suggestion data entered by the user.
+        $suggestions = $this->fetch_from_context($context, 'values');
+
+        // Convert it to an list and reverse it (as higher priority items
+        // should be on the bottom).
+        $suggestions = array_reverse(explode("\n", $suggestions));
+
+        // Append the suggested list to the existing list.
+        $vars['theme_hook_suggestions'] = array_merge($vars['theme_hook_suggestions'], $suggestions);
+      }
+    }
+  }
+}
+

+ 30 - 5
sites/all/modules/contrib/admin/context/tests/context.reactions.test

@@ -87,20 +87,45 @@ class ContextReactionBlockAjaxTest extends DrupalWebTestCase {
     );
   }
 
+  function setUp() {
+    parent::setUp('context', 'context_ui', 'ctools');
+    $admin_user = $this->drupalCreateUser(array('context ajax block access'));
+    $this->drupalLogin($admin_user);
+  }
+
+  function test() {
+    $this->drupalGet('node', array(
+      'query' => array('context_block' => 'user-online,testcontext')
+    ));
+
+    $this->assertText('"status":1', 'Successful return status.');
+    $this->assertText('Who\\u0027s online', 'Expected text in block data.');
+  }
+}
+
+class ContextReactionBlockAjaxAccessTest extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Reaction: block ajax access',
+      'description' => 'Test block reaction ajax access behavior.',
+      'group' => 'Context',
+    );
+  }
+
   function setUp() {
     parent::setUp('context', 'ctools');
-    $admin_user = $this->drupalCreateUser(array('administer site configuration'));
+    $admin_user = $this->drupalCreateUser();
     $this->drupalLogin($admin_user);
   }
 
   function test() {
-    $token = drupal_hmac_base64('user-online', $this->session_id . drupal_get_private_key() . drupal_get_hash_salt());
     $this->drupalGet('node', array(
-      'query' => array('context_block' => 'user-online,testcontext', 'context_token' => $token)
+      'query' => array('context_block' => 'user-online,testcontext')
     ));
 
-    $this->assertText('"status":1', 'Successful return status. $drupal_hash_salt must be set explicitly for this test to pass');
-    $this->assertText('Who\\u0027s online', 'Expected text in block data. drupal_hash_salt must be set explicitly for this test to pass');
+    $this->assertText('"status":0', 'Failed return status.');
   }
 }
 

+ 10 - 5
sites/all/modules/contrib/admin/context/theme/context_reaction_block.theme.inc

@@ -121,11 +121,16 @@ function template_preprocess_context_block_browser(&$vars) {
  * Preprocessor for theme('context_block_browser_item').
  */
 function template_preprocess_context_block_browser_item(&$vars) {
-  static $added = array();
   $vars['bid'] = $vars['block']->bid;
   $vars['info'] = check_plain($vars['block']->info);
-  if (empty($added[$vars['bid']])) {
-    drupal_add_js(array('contextBlockEditor' => array('block_tokens' => array($vars['bid'] => drupal_get_token($vars['bid'])))), 'setting');
-    $added[$vars['bid']] = TRUE;
-  }
+}
+
+/**
+ * Theme wrapper for editable blocks.
+ *
+ * @ingroup themeable
+ */
+function theme_context_block_edit_wrap($vars) {
+  $block = $vars['element']['#block'];
+  return $vars['element']['#children'] . "<a id='context-block-{$block->module}-{$block->delta}' class='context-block editable edit-{$block->context}'></a>";
 }

+ 3 - 54
sites/all/modules/contrib/admin/print/INSTALL.txt

@@ -11,65 +11,14 @@ PDF TOOL
 --------
 
 The print_pdf module requires the use of an external PDF generation tool.
-The currently supported tools are dompdf, TCPDF and wkhtmltopdf.  Please
-note that any errors/bugs in those tools need to be reported and fixed by
-their maintainers.  DO NOT report bugs in those tools in the print module's
-issue queue at Drupal.org.
+Please note that any errors/bugs in those tools need to be reported and
+fixed by their maintainers.  DO NOT report bugs in those tools in the print
+module's issue queue at drupal.org.
 
 supported paths:
   * print module lib directory (usually sites/all/modules/print/lib)
   * libraries directory (sites/all/libraries)
 
-dompdf support:
-  The dompdf tool produces results that are more faithful to the HTML
-  printer-friendly page. Good support of CSS 2.1 and partially CSS3.
-
-  1. Download dompdf from http://code.google.com/p/dompdf/downloads/list
-  2. Extract the contents of the downloaded package into one of the
-  supported paths.
-  3. Check if dompdf_config.inc.php fits your installation. In 99% of cases,
-  no changes are necessary, so just try to use it and only edit anything if
-  the PDF generation fails.
-  4. Grant write access to the lib/fonts directory to your webserver user.
-  5. If you're using dompdf-0.5.1, delete the dompdf.php file as it contains
-  a security vulnerability
-  6. If you're using dompdf-0.6 or later, you can try to enable the Unicode
-  support, but you'll need to add some Unicode fonts. See 
-  http://groups.google.com/group/dompdf/browse_thread/thread/9f7bc0162b04d5cf
-  for further info on this.
-  7. Check http://code.google.com/p/dompdf/ for further information.
-
-TCPDF support:
-  TCPDF's support for CSS is considerably worse than the other tools.
-  Unicode is supported (use of Unicode fonts result in HUGE files).  Page
-  header and footer are supported. This module requires TCPDF >= 5.9.012.
-
-  1. Download TCPDF from http://sourceforge.net/projects/tcpdf/
-  2. Extract the contents of the downloaded package into one of the
-  supported paths.  There is no need to modify the config/tcpdf_config.php
-  file, as the module self-configures TCPDF.
-  3. Grant write access to the cache and images directories to your
-  webserver user.
-  4. Check http://tcpdf.sourceforge.net/ for further information.
-
-wkhtmltopdf support:
-  wkhtmltopdf is a webkit-based tool that actually is a browser in order to
-  generate the PDF.  Resource hungry: expect to need some 30Mb+ of RAM and
-  some seconds of CPU power.  The static binaries may need additional
-  libraries in your site, which may present problems in shared hosting
-  environments.  The best, if you can run it.
-
-  1. Download wkhtmltopdf from
-  http://code.google.com/p/wkhtmltopdf/downloads/list. You can choose to
-  download the source and compile it or simply download the static binary,
-  which doesn't require you to compile anything. Note that the compiled
-  version may require a running X server (static uses patched libs that can
-  work without one).
-  2. Place the wkhtmltopdf executable into one of the supported paths. 
-  (usually sites/all/modules/print/lib).  You can also place a symbolic link
-  to the executable.
-  3. Check http://code.google.com/p/wkhtmltopdf/ for further information.
-
 UPDATE
 ------
 

+ 2 - 7
sites/all/modules/contrib/admin/print/css/print-rtl.css

@@ -1,10 +1,5 @@
-
-body {
-  direction: rtl;
-}
-th {
-  text-align: right;
-}
+body {direction: rtl;}
+th {text-align: right;}
 .print-links,
 .print-source_url,
 .print-taxonomy {

+ 6 - 19
sites/all/modules/contrib/admin/print/css/print.css

@@ -1,4 +1,3 @@
-
 body {
   margin: 1em;
   background-color: #fff;
@@ -9,21 +8,11 @@ th {
   color: #006;
   border-bottom: 1px solid #ccc;
 }
-tr.odd {
-  background-color: #ddd;
-}
-tr.even {
-  background-color: #fff;
-}
-td {
-  padding: 5px;
-}
-#menu {
-  visibility: hidden;
-}
-#main {
-  margin: 1em;
-}
+tr.odd {background-color: #ddd;}
+tr.even {background-color: #fff;}
+td {padding: 5px;}
+#menu {visibility: hidden;}
+#main {margin: 1em;}
 a:link {color: #000;}
 a:visited {color: #000;}
 a:hover {color: #00f;}
@@ -35,9 +24,7 @@ img.print-logo {border: 0;}
 .print-title {}
 .print-submitted {font-size: small;}
 .print-created {font-size: small;}
-.print-taxonomy {
-  text-align: right;
-}
+.print-taxonomy {text-align: right;}
 .print-taxonomy li {display: inline;}
 .print-content {}
 .print-hr {

BIN
sites/all/modules/contrib/admin/print/icons/mail_icon.gif


BIN
sites/all/modules/contrib/admin/print/icons/pdf_icon.gif


BIN
sites/all/modules/contrib/admin/print/icons/print_icon.gif


BIN
sites/all/modules/contrib/admin/print/icons/print_icon.png


+ 151 - 0
sites/all/modules/contrib/admin/print/includes/print.drush.inc

@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * @file
+ * common drush functions for the print submodules.
+ */
+
+/**
+ * Download and extract the lib
+ *
+ * @param string $library
+ *   library to download.
+ * @param string $url
+ *   URL of the file to download
+ */
+function _print_drush_download_lib($library, $url) {
+  $path = drush_get_option('path');
+  if (empty($path)) {
+    $path = drush_get_context('DRUSH_DRUPAL_ROOT') . '/sites/all/libraries';
+  }
+
+  // Create the path if it does not exist.
+  if (!is_dir($path)) {
+    drush_op('mkdir', $path);
+    drush_log(dt('Directory @path was created', array('@path' => $path)), 'notice');
+  }
+
+  // Chdir to the download location.
+  $olddir = getcwd();
+  drush_op('chdir', $path);
+
+  // Warn about an existing dir
+  if (is_dir($library)) {
+    // drush_op('rmdir', $library); // Directory must be empty for the php rmdir to work..
+    drush_log(dt('An existing @library was overwritten at @path', array('@library' => $library, '@path' => $path . '/' . $library)), 'notice');
+  }
+
+  // Download the archive
+  $filename = _print_drush_download_file($url);
+  if ($filename) {
+    $extract_ret = _print_drush_download_extract($filename);
+    if ($extract_ret) {
+      // Remove the archive
+      drush_op('unlink', $filename);
+      drush_log(dt('@file has been downloaded and extracted in @path', array('@file' => $filename, '@path' => $path)), 'success');
+    }
+    else {
+      drush_log(dt('@file has been downloaded to @path, but extract failed. Check that you have the necessary program installed, and if necessary extract it manually.',
+                array('@file' => $filename, '@path' => $path)), 'warning');
+    }
+  }
+  else {
+    drush_log(dt('Drush was unable to download @library to @path', array('@library' => $library, '@path' => $path)), 'error');
+  }
+
+  // Set working directory back to the previous working directory.
+  drush_op('chdir', $olddir);
+}
+
+/**
+ * Download a file using wget or curl
+ *
+ * Adapted from a function in drush/includes/drush.inc to support 302 redirects.
+ *
+ * @param string $download_url
+ *   The path to the file to download
+ *
+ * @return string
+ *   The filename that was downloaded, or NULL if the file could not be
+ *   downloaded.
+ */
+function _print_drush_download_file($download_url) {
+  $wget_ret = drush_shell_exec("wget -nv --trust-server-names %s", $download_url);
+
+  if (!drush_get_context('DRUSH_SIMULATE')) {
+    if ($wget_ret) {
+      // Get the filename of the saved file from the output
+      $wget_out = explode('"', array_shift(drush_shell_exec_output()));
+      $filename = $wget_out[1];
+    }
+    else {
+      $tempnam = uniqid('print_drush_');
+
+      $curl_ret = drush_shell_exec("curl -s -L -o %s %s -w '%%{url_effective}'", $tempnam, $download_url);
+      if ($curl_ret) {
+        // File was donwloaded with the tempname
+
+        // Find the effective name
+        $filename = explode('/', array_shift(drush_shell_exec_output()));
+        $filename = array_pop($filename);
+
+        // Rename file from tempname to effective name
+        if (!drush_op('rename', $tempnam, './' . $filename)) {
+          $filename = $tempnam;
+        }
+      }
+      else {
+        $filename = FALSE;
+      }
+    }
+  }
+  else {
+    $filename = basename($download_url);
+  }
+
+  return $filename;
+}
+
+/**
+ * Helper to extract the downloaded zip/tar archive.
+ *
+ * @param string $filename
+ *   filename of the file to extract
+ *
+ * @return bool
+ *   TRUE on success, FALSE on failure
+ */
+function _print_drush_download_extract($filename) {
+  $arch_ret = FALSE;
+
+  if (drush_op('is_file', $filename)) {
+    switch (drush_op('mime_content_type', $filename)) {
+      case 1:
+        $arch_ret = TRUE;
+        break;
+      case 'application/zip':
+        // Decompress the zip archive
+        $arch_ret = drush_shell_exec('unzip -qq -o %s', $filename);
+        // ZIP archives usually get the access rights wrong
+        drush_log(dt('@filename is a Zip file. Check the access permissions of the extracted files.', array('@filename' => $filename)), 'warning');
+        break;
+      case 'application/x-gzip':
+        // Decompress the tar gz archive
+        $arch_ret = drush_shell_exec('tar xzf %s', $filename);
+        break;
+      case 'application/x-bzip2':
+        // Decompress the tar bz2 archive
+        $arch_ret = drush_shell_exec('tar xjf %s', $filename);
+        break;
+      case 'application/x-xz':
+        // Decompress the tar xz archive
+        $arch_ret = drush_shell_exec('tar xJf %s', $filename);
+        break;
+    }
+  }
+  else {
+    drush_log(dt('@filename not found.', array('@filename' => $filename)), 'error');
+  }
+
+  return $arch_ret;
+}

+ 100 - 0
sites/all/modules/contrib/admin/print/includes/print.inc

@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @file
+ * Common functions used by several of the print modules
+ *
+ * @ingroup print
+ */
+
+/**
+ * Auxiliary function to scan all module directories for a given library.
+ *
+ * @param string $lib
+ *   The machine name of a library to return the path for.
+ * @param string $mask
+ *   The preg_match() regular expression of the files to find.
+ *
+ * @return array
+ *   An array of the filenames matching the provided mask.
+ */
+function _print_scan_libs($lib, $mask) {
+  $tools = array_keys(file_scan_directory(drupal_get_path('module', 'print'), $mask));
+  $tools = array_merge($tools, array_keys(file_scan_directory(PRINT_LIB_PATH, $mask)));
+  if (module_exists('libraries')) {
+    $tools = array_merge($tools, array_keys(file_scan_directory(libraries_get_path($lib), $mask)));
+  }
+
+  return array_unique($tools);
+}
+
+/**
+ * Callback function for the preg_replace_callback replacing spaces with %20
+ *
+ * Replace spaces in URLs with %20
+ *
+ * @param array $matches
+ *   array with the matched tag patterns, usually <a...>+text+</a>
+ *
+ * @return string
+ *   tag with re-written URL
+ */
+function _print_replace_spaces($matches) {
+  // first, split the html into the different tag attributes
+  $pattern = '!\s*(\w+\s*=\s*"(?:\\\"|[^"])*")\s*|\s*(\w+\s*=\s*\'(?:\\\\\'|[^\'])*\')\s*|\s*(\w+\s*=\s*\w+)\s*|\s+!';
+  $attribs = preg_split($pattern, $matches[1], -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
+  foreach ($attribs as $key => $value) {
+    $attribs[$key] = preg_replace('!(\w)\s*=\s*(.*)!', '$1=$2', $value);
+  }
+
+  $size = count($attribs);
+  for ($i=1; $i < $size; $i++) {
+    // If the attribute is href or src, we may need to rewrite the URL in the value
+    if (preg_match('!^(?:href|src)\s*?=(.*)!i', $attribs[$i], $urls) > 0) {
+      $url = trim($urls[1], " \t\n\r\0\x0B\"'");
+      $new_url = str_replace(' ', '%20', $url);
+      $matches[1] = str_replace($url, $new_url, $matches[1]);
+    }
+  }
+
+  $ret = '<' . $matches[1] . '>';
+  if (count($matches) == 4) {
+    $ret .= $matches[2] . $matches[3];
+  }
+
+  return $ret;
+}
+
+/**
+ * Convert image paths to the file:// protocol
+ *
+ * In some Drupal setups, the use of the 'private' filesystem or Apache's
+ * configuration prevent access to the images of the page. This function
+ * tries to circumnvent those problems by accessing files in the local
+ * filesystem.
+ *
+ * @param string $html
+ *   contents of the post-processed template already with the node data
+ * @param bool $images_via_file
+ *   if TRUE, convert also files in the 'public' filesystem to local paths
+ *
+ * @return string
+ *   converted file names
+ */
+function _print_access_images_via_file($html, $images_via_file) {
+  global $base_url, $language;
+
+  $lang = (function_exists('language_negotiation_get_any') && language_negotiation_get_any('locale-url')) ? $language->language : '';
+
+  // Always convert private to local paths
+  $pattern = "!(<img\s[^>]*?src\s*?=\s*?['\"]?)${base_url}/(?:(?:index.php)?\?q=)?(?:${lang}/)?system/files/([^>]*?>)!is";
+  $replacement = '$1file://' . realpath(variable_get('file_private_path', '')) . '/$2';
+  $html = preg_replace($pattern, $replacement, $html);
+  if ($images_via_file) {
+    $pattern = "!(<img\s[^>]*?src\s*?=\s*?['\"]?)${base_url}/(?:(?:index.php)?\?q=)?(?:${lang}/)?([^>]*?>)!is";
+    $replacement = '$1file://' . dirname($_SERVER['SCRIPT_FILENAME']) . '/$2';
+    $html = preg_replace($pattern, $replacement, $html);
+  }
+
+  return $html;
+}

+ 21 - 196
sites/all/modules/contrib/admin/print/print.admin.inc

@@ -11,7 +11,7 @@
  */
 
 /**
- * Menu callback for the Printer-friendly pages module settings form.
+ * Form constructor for the Printer-friendly pages module settings form.
  *
  * @ingroup forms
  */
@@ -168,7 +168,7 @@ function print_main_settings() {
 }
 
 /**
- * Validate print_main_settings form.
+ * Form validation handler for print_main_settings().
  */
 function _print_main_settings_validate($form, &$form_state) {
   global $base_root;
@@ -188,123 +188,18 @@ function _print_main_settings_validate($form, &$form_state) {
 }
 
 /**
- * Menu callback for the Printer-friendly pages HTML settings form.
+ * Form constructor for the Printer-friendly pages HTML settings form.
  *
  * @ingroup forms
  */
 function print_html_settings() {
+  $link = print_print_link();
+
   $form['settings'] = array(
     '#type' => 'fieldset',
     '#title' => t('Web page options'),
   );
 
-  $form['settings']['print_html_link_pos'] = array(
-    '#type' => 'checkboxes',
-    '#title' => t('Printer-friendly page link'),
-    '#default_value' => variable_get('print_html_link_pos', drupal_json_decode(PRINT_HTML_LINK_POS_DEFAULT)),
-    '#options' => array('link' => t('Links area'), 'corner' => t('Content corner'), 'block' => t('Block'), 'help' => t('Help area')),
-    '#description' => t('Choose the location of the link(s) to the printer-friendly page. The Links area is usually below the node content, whereas the Content corner is placed in the upper-right corner of the node content. Unselect all options to disable the link. Even if the link is disabled, you can still view the print version of a node by going to !path/nid where nid is the numeric id of the node.', array('!path' => PRINT_PATH)),
-  );
-
-  $form['settings']['print_html_link_teaser'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Display printer-friendly link in teaser'),
-    '#default_value' => variable_get('print_html_link_teaser', PRINT_HTML_LINK_TEASER_DEFAULT),
-    '#description' => t('Enabling this will display the link in teaser mode.'),
-  );
-
-  $form['settings']['adv_link'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Advanced link options'),
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-  );
-
-  $form['settings']['adv_link']['print_html_show_link'] = array(
-    '#type' => 'radios',
-    '#title' => t('Link style'),
-    '#default_value' => variable_get('print_html_show_link', PRINT_HTML_SHOW_LINK_DEFAULT),
-    '#options' => array(1 => t('Text only'), 2 => t('Icon only'), 3 => t('Icon and Text')),
-    '#description' => t('Select the visual style of the link.'),
-  );
-
-  $form['settings']['adv_link']['print_html_link_use_alias'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Use URL alias instead of node ID'),
-    '#default_value' => variable_get('print_html_link_use_alias', PRINT_HTML_LINK_USE_ALIAS_DEFAULT),
-    '#description' => t('Enabling this will create the link using the URL alias instead of the node ID.'),
-  );
-
-  $form['settings']['adv_link']['print_html_link_class'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Link class'),
-    '#default_value' => variable_get('print_html_link_class', PRINT_HTML_LINK_CLASS_DEFAULT),
-    '#size' => 60,
-    '#maxlength' => 250,
-    '#description' => t('This can be used by themers to change the link style or by jQuery modules to open in a new window (e.g. greybox or thickbox). Multiple classes can be specified, separated by spaces.'),
-  );
-
-  $form['settings']['adv_link']['print_html_node_link_visibility'] = array(
-    '#type' => 'radios',
-    '#title' => t('Link visibility'),
-    '#default_value' => variable_get('print_html_node_link_visibility', PRINT_HTML_NODE_LINK_VISIBILITY_DEFAULT),
-    '#options' => array(t('Show on every page except the listed pages.'), t('Show on only the listed pages.')),
-  );
-
-  $form['settings']['adv_link']['print_html_node_link_pages'] = array(
-    '#type' => 'textarea',
-    '#default_value' => variable_get('print_html_node_link_pages', PRINT_HTML_NODE_LINK_PAGES_DEFAULT),
-    '#rows' => 3,
-    '#description' => t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>')),
-  );
-
-  if (module_exists('php')) {
-    $access = user_access('use PHP for settings');
-
-    if ($form['settings']['adv_link']['print_html_node_link_visibility']['#default_value'] == 2 && !$access) {
-      $form['settings']['adv_link']['print_html_node_link_visibility'] = array('#type' => 'value', '#value' => 2);
-      $form['settings']['adv_link']['print_html_node_link_pages'] = array('#type' => 'value', '#value' => $form['settings']['adv_link']['print_html_node_link_pages']['#default_value']);
-    }
-    elseif ($access) {
-      $form['settings']['adv_link']['print_html_node_link_visibility']['#options'][] = t('Show if the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
-      $form['settings']['adv_link']['print_html_node_link_pages']['#description'] .= ' ' . t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can break your Drupal site.', array('%php' => '<?php ?>'));
-    }
-  }
-
-  $form['settings']['adv_link']['print_html_sys_link_visibility'] = array(
-    '#type' => 'radios',
-    '#title' => t('Show link in system (non-content) pages'),
-    '#description' => 'Any page that is not a Drupal node. Usually pages generated by Drupal or a module such as Views or Panels.',
-    '#default_value' => variable_get('print_html_sys_link_visibility', PRINT_HTML_SYS_LINK_VISIBILITY_DEFAULT),
-    '#options' => array(t('Show on every page except the listed pages.'), t('Show on only the listed pages.')),
-  );
-
-  $form['settings']['adv_link']['print_html_sys_link_pages'] = array(
-    '#type' => 'textarea',
-    '#default_value' => variable_get('print_html_sys_link_pages', PRINT_HTML_SYS_LINK_PAGES_DEFAULT),
-    '#rows' => 3,
-    '#description' => t('Setting this option will add a printer-friendly version page link on pages created by Drupal or the enabled modules.') . '<br />' .
-                      t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>')),
-  );
-
-  if (module_exists('php')) {
-    if ($form['settings']['adv_link']['print_html_sys_link_visibility']['#default_value'] == 2 && !$access) {
-      $form['settings']['adv_link']['print_html_sys_link_visibility'] = array('#type' => 'value', '#value' => 2);
-      $form['settings']['adv_link']['print_html_sys_link_pages'] = array('#type' => 'value', '#value' => $form['settings']['adv_link']['print_html_sys_link_pages']['#default_value']);
-    }
-    elseif ($access) {
-      $form['settings']['adv_link']['print_html_sys_link_visibility']['#options'][] = t('Show if the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
-      $form['settings']['adv_link']['print_html_sys_link_pages']['#description'] .= ' ' . t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can break your Drupal site.', array('%php' => '<?php ?>'));
-    }
-  }
-
-  $form['settings']['adv_link']['print_html_book_link'] = array(
-    '#type' => 'radios',
-    '#title' => t('Link in book hierarchy nodes'),
-    '#default_value' => variable_get('print_html_book_link', PRINT_HTML_BOOK_LINK_DEFAULT),
-    '#options' => array(t('Book module link not modified'), t('Current page and sub-pages'), t('Current page only')),
-  );
-
   $form['settings']['print_html_new_window'] = array(
     '#type' => 'checkbox',
     '#title' => t('Open the printer-friendly version in a new window'),
@@ -326,18 +221,18 @@ function print_html_settings() {
     '#description' => t("When the above options are enabled, this option will close the window after its contents are printed."),
   );
 
-  $form['settings']['print_display_sys_urllist'] = array(
+  $form['settings']['print_html_display_sys_urllist'] = array(
     '#type' => 'checkbox',
     '#title' => t('Printer-friendly URLs list in system pages'),
-    '#default_value' => variable_get('print_display_sys_urllist', PRINT_TYPE_SYS_URLLIST_DEFAULT),
+    '#default_value' => variable_get('print_html_display_sys_urllist', PRINT_TYPE_SYS_URLLIST_DEFAULT),
     '#description' => t('Enabling this option will display a list of printer-friendly destination URLs at the bottom of the page.'),
   );
 
   $form['settings']['print_robots_settings'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Robots META tags'),
-      '#collapsible' => TRUE,
-      '#collapsed' => TRUE,
+    '#type' => 'fieldset',
+    '#title' => t('Robots META tags'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
   );
 
   $form['settings']['print_robots_settings']['print_robots_noindex'] = array(
@@ -361,92 +256,22 @@ function print_html_settings() {
     '#description' => t('Non-standard tag to instruct search engines to not show a "Cached" link for your printer-friendly pages. Recognized by Googlebot.'),
   );
 
-  return system_settings_form($form);
-}
-
-/**
- * Menu callback for the common print module text strings settings form
- *
- * @ingroup forms
- */
-function print_main_strings_settings() {
-  drupal_set_message(t("Saving these strings will disable their translation via Drupal's language system. Use the reset button to return them to the original state."), 'warning');
-
-  $form['print_main_text'] = array(
+  $form['settings']['link_text'] = array(
     '#type' => 'fieldset',
-    '#title' => t('Text strings'),
-  );
-
-  $form['print_main_text']['print_text_published'] = array(
-    '#type' => 'textfield',
-    '#default_value' => variable_get('print_text_published', t('Published on %site_name')),
-  );
-  $form['print_main_text']['print_text_source_url'] = array(
-    '#type' => 'textfield',
-    '#default_value' => variable_get('print_text_source_url', t('Source URL')),
-  );
-  $form['print_main_text']['print_text_retrieved'] = array(
-    '#type' => 'textfield',
-    '#default_value' => variable_get('print_text_retrieved', t('retrieved on %date')),
-  );
-  $form['print_main_text']['print_text_links'] = array(
-    '#type' => 'textfield',
-    '#default_value' => variable_get('print_text_links', t('Links')),
-  );
-  $form['print_main_text']['reset'] = array(
-    '#type' => 'submit',
-    '#value' => t('Reset to defaults'),
-    '#submit' => array('print_main_strings_settings_delete'),
+    '#title' => t('Custom link text'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
   );
-
-  return system_settings_form($form);
-}
-
-/**
- * Reset button callback for text strings settings form
- *
- * @ingroup forms
- */
-function print_main_strings_settings_delete() {
-  variable_del('print_text_published');
-  variable_del('print_text_source_url');
-  variable_del('print_text_retrieved');
-  variable_del('print_text_links');
-}
-
-/**
- * Menu callback for the printer-friendly version text strings settings form
- *
- * @ingroup forms
- */
-function print_html_strings_settings() {
-  drupal_set_message(t("Saving these strings will disable their translation via Drupal's language system. Use the reset button to return them to the original state."), 'warning');
-
-  $form['print_html_text'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Text strings'),
+  $form['settings']['link_text']['print_html_link_text_enabled'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable custom link text'),
+    '#default_value' => variable_get('print_html_link_text_enabled', PRINT_TYPE_LINK_TEXT_ENABLED_DEFAULT),
   );
-
-  $form['print_html_text']['print_html_link_text'] = array(
+  $form['settings']['link_text']['print_html_link_text'] = array(
     '#type' => 'textfield',
-    '#title' => t('Link text'),
-    '#default_value' => variable_get('print_html_link_text', t('Printer-friendly version')),
+    '#default_value' => variable_get('print_html_link_text', $link['text']),
     '#description' => t('Text used in the link to the printer-friendly version.'),
   );
-  $form['print_html_text']['reset'] = array(
-    '#type' => 'submit',
-    '#value' => t('Reset to defaults'),
-    '#submit' => array('print_html_strings_settings_delete'),
-  );
 
   return system_settings_form($form);
 }
-
-/**
- * Reset button callback for text strings settings form
- *
- * @ingroup forms
- */
-function print_html_strings_settings_delete() {
-  variable_del('print_html_link_text');
-}

+ 122 - 0
sites/all/modules/contrib/admin/print/print.api.php

@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * @file
+ * Main API entry point for the Printer, email and PDF versions
+ *
+ * @ingroup print
+ */
+
+/**
+ * @defgroup print Files
+ *
+ * Files used by the print module, grouped by sub-module
+ *
+ * - Printer-friendly pages
+ *   - @link print.api.php API @endlink
+ *   - @link print.module Module main file @endlink
+ *   - @link print.pages.inc HTML generation @endlink
+ *   - @link print.admin.inc Settings form @endlink
+ *   - @link print.install (Un)Install routines @endlink
+ *   - @link print.tpl.php Page generation template @endlink
+ *   - @link print.views.inc Views integration @endlink
+ *   - @link print_join_page_counter.inc Views join handler @endlink
+ * - Send by email
+ *   - @link print_mail.module Module main file @endlink
+ *   - @link print_mail.inc Mail form and send mail routine @endlink
+ *   - @link print_mail.admin.inc Settings form @endlink
+ *   - @link print_mail.install (Un)Install routines @endlink
+ *   - @link print_mail.views.inc Views integration @endlink
+ * - PDF version
+ *   - @link print_pdf.api.php API @endlink
+ *   - @link print_pdf.module Module main file @endlink
+ *   - @link print_pdf.pages.inc PDF generation @endlink
+ *   - @link print_pdf.admin.inc Settings form @endlink
+ *   - @link print_pdf.install (Un)Install routines @endlink
+ *   - @link print_pdf.drush.inc Drush commands @endlink
+ *   - @link print_pdf.views.inc Views integration @endlink
+ *   - PDF library handlers:
+ *     - dompdf
+ *       - @link print_pdf_dompdf.module Module main file @endlink
+ *       - @link print_pdf_dompdf.pages.inc PDF generation @endlink
+ *       - @link print_pdf_dompdf.admin.inc Settings form @endlink
+ *       - @link print_pdf_dompdf.install (Un)Install routines @endlink
+ *       - @link print_pdf_dompdf.drush.inc Drush commands @endlink
+ *     - mPDF
+ *       - @link print_pdf_mpdf.module Module main file @endlink
+ *       - @link print_pdf_mpdf.pages.inc PDF generation @endlink
+ *       - @link print_pdf_mpdf.drush.inc Drush commands @endlink
+ *     - TCPDF
+ *       - @link print_pdf_tcpdf.module Module main file @endlink
+ *       - @link print_pdf_tcpdf.pages.inc PDF generation @endlink
+ *       - @link print_pdf_tcpdf.admin.inc Settings form @endlink
+ *       - @link print_pdf_tcpdf.install (Un)Install routines @endlink
+ *       - @link print_pdf_tcpdf.class.inc Auxiliary PHP5 class @endlink
+ *       - @link print_pdf_tcpdf.drush.inc Drush commands @endlink
+ *     - wkhtmltopdf
+ *       - @link print_pdf_wkhtmltopdf.module Module main file @endlink
+ *       - @link print_pdf_wkhtmltopdf.pages.inc PDF generation @endlink
+ *       - @link print_pdf_wkhtmltopdf.admin.inc Settings form @endlink
+ *       - @link print_pdf_wkhtmltopdf.install (Un)Install routines @endlink
+ *       - @link print_pdf_wkhtmltopdf.drush.inc Drush commands @endlink
+ * - EPUB version
+ *   - @link print_epub.api.php API @endlink
+ *   - @link print_epub.module Module main file @endlink
+ *   - @link print_epub.pages.inc EPUB generation @endlink
+ *   - @link print_epub.admin.inc Settings form @endlink
+ *   - @link print_epub.install (Un)Install routines @endlink
+ *   - @link print_epub.drush.inc Drush commands @endlink
+ *   - @link print_epub.views.inc Views integration @endlink
+ *   - EPUB library handlers:
+ *     - phpepub
+ *       - @link print_epub_phpepub.module Module main file @endlink
+ *       - @link print_epub_phpepub.pages.inc EPUB generation @endlink
+ *       - @link print_epub_phpepub.drush.inc Drush commands @endlink
+ * - User Interface (Links)
+ *   - @link print_ui.api.php API @endlink
+ *   - @link print_ui.module Module main file @endlink
+ *   - @link print_ui.admin.inc Settings form @endlink
+ */
+
+/**
+ * @defgroup print_hooks Hooks
+ *
+ * Hooks used in the print module
+ */
+
+/**
+ * @defgroup print_themeable Themeable functions
+ *
+ * Default theme implementations of the print module
+ */
+
+/**
+ * @defgroup print_api API
+ *
+ * Functions that are provided for use by third-party code.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Alters the URL in the URL list.
+ *
+ * This hook is useful for third-party modules that would prefer to display
+ * something other than the naked URL in the URL list (e.g. glossary terms,
+ * etc.).
+ *
+ * @param string $url
+ *   the url to be modified.
+ *
+ * @ingroup print_hooks
+ */
+function hook_print_url_list_alter(&$url) {
+  $url = 'foo';
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */

+ 6 - 10
sites/all/modules/contrib/admin/print/print.info

@@ -1,18 +1,14 @@
 name = "Printer-friendly pages"
-description = "Adds a printer-friendly version link to content and administrative pages."
-core=7.x
+description = "Generates a printer-friendly version of Drupal pages."
+core = 7.x
 package = "Printer, email and PDF versions"
-files[] = print.module
-files[] = print.admin.inc
-files[] = print.pages.inc
-files[] = print.install
-files[] = print.views.inc
 files[] = print_join_page_counter.inc
+dependencies[] = node
 configure = admin/config/user-interface/print
 
-; Information added by drupal.org packaging script on 2012-09-04
-version = "7.x-1.2"
+; Information added by Drupal.org packaging script on 2014-04-02
+version = "7.x-2.0"
 core = "7.x"
 project = "print"
-datestamp = "1346768900"
+datestamp = "1396426766"
 

+ 70 - 34
sites/all/modules/contrib/admin/print/print.install

@@ -35,46 +35,39 @@ function print_enable() {
  * Implements hook_uninstall().
  */
 function print_uninstall() {
-  variable_del('print_settings');
-  variable_del('print_sourceurl_settings');
-  variable_del('print_html_settings');
-  variable_del('print_robot_settings');
-  variable_del('print_logo_url');
-  variable_del('print_logo_options');
+  variable_del('print_comments');
   variable_del('print_css');
+  variable_del('print_footer_options');
+  variable_del('print_footer_user');
+  variable_del('print_html_display_sys_urllist');
+  variable_del('print_html_link_text');
+  variable_del('print_html_link_text_enabled');
+  variable_del('print_html_new_window');
+  variable_del('print_html_sendtoprinter');
+  variable_del('print_html_windowclose');
   variable_del('print_keep_theme_css');
-  variable_del('print_urls');
-  variable_del('print_urls_anchors');
-  variable_del('print_comments');
+  variable_del('print_logo_options');
+  variable_del('print_logo_url');
   variable_del('print_newwindow');
-  variable_del('print_sourceurl_enabled');
+  variable_del('print_robots_noarchive');
+  variable_del('print_robots_nofollow');
+  variable_del('print_robots_noindex');
   variable_del('print_sourceurl_date');
+  variable_del('print_sourceurl_enabled');
   variable_del('print_sourceurl_forcenode');
-  variable_del('print_html_show_link');
+  variable_del('print_urls');
+  variable_del('print_urls_anchors');
+
+  variable_del('print_html_book_link');
+  variable_del('print_html_link_class');
   variable_del('print_html_link_pos');
   variable_del('print_html_link_teaser');
-  variable_del('print_html_node_link_visibility');
-  variable_del('print_html_node_link_pages');
-  variable_del('print_html_link_class');
-  variable_del('print_html_sys_link_visibility');
-  variable_del('print_html_sys_link_pages');
-  variable_del('print_html_book_link');
-  variable_del('print_html_new_window');
-  variable_del('print_html_sendtoprinter');
-  variable_del('print_html_windowclose');
-  variable_del('print_display_sys_urllist');
-  variable_del('print_robots_noindex');
-  variable_del('print_robots_nofollow');
-  variable_del('print_robots_noarchive');
-  variable_del('print_footer_options');
-  variable_del('print_footer_user');
-  variable_del('print_html_link_text');
   variable_del('print_html_link_use_alias');
-  variable_del('print_text_links');
-  variable_del('print_text_published');
-  variable_del('print_text_retrieved');
-  variable_del('print_text_source_url');
-  $settings = db_query("SELECT name FROM {variable} WHERE name LIKE 'print\_display\_%'");
+  variable_del('print_html_show_link');
+  variable_del('print_html_sys_link_pages');
+  variable_del('print_html_sys_link_visibility');
+
+  $settings = db_query("SELECT name FROM {variable} WHERE name LIKE 'print\_html\_display\_%'");
   foreach ($settings as $variable) {
     variable_del($variable->name);
   }
@@ -126,7 +119,7 @@ function print_schema() {
     'fields' => array(
       'path' => array(
         'type' => 'varchar',
-        'length' => 128,
+        'length' => 255,
         'not null' => TRUE,
         'description' => 'Page path',
       ),
@@ -166,12 +159,55 @@ function print_update_7000(&$sandbox) {
   update_fix_d7_block_deltas($sandbox, $renamed_deltas, array());
 }
 
+/**
+ * Enable the print UI module
+ */
+function print_update_7199(&$sandbox) {
+  module_enable(array('print_ui'), FALSE);
+}
+
+/**
+ * Delete old variables
+ */
+function print_update_7200(&$sandbox) {
+  variable_del('print_settings');
+  variable_del('print_sourceurl_settings');
+  variable_del('print_html_settings');
+  variable_del('print_robot_settings');
+
+  variable_del('print_html_node_link_pages');
+  variable_del('print_html_node_link_visibility');
+
+  variable_del('print_text_links');
+  variable_del('print_text_published');
+  variable_del('print_text_retrieved');
+  variable_del('print_text_source_url');
+
+  $settings = db_query("SELECT name FROM {variable} WHERE name LIKE 'print\_display\_%'");
+  foreach ($settings as $variable) {
+    $name = $variable->name;
+
+    variable_set(str_replace('print_', 'print_html_', $name), variable_get($name));
+    variable_del($name);
+  }
+}
+
 /**
  * Enable block and help area links
  */
-function print_update_7101(&$sandbox) {
+function print_update_7202(&$sandbox) {
   $link_pos = variable_get('print_html_link_pos', drupal_json_decode('{ "link": "link", "block": "block", "help": "help" }'));
   $link_pos['block'] = 'block';
   $link_pos['help'] = 'help';
   variable_set('print_html_link_pos', $link_pos);
 }
+
+/**
+ * Increase size of the path field in the print_page_counter table
+ */
+function print_update_7203(&$sandbox) {
+  db_drop_primary_key('print_page_counter');
+  db_change_field('print_page_counter', 'path', 'path',
+    array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'description' => 'Page path'),
+    array('primary key' => array('path')));
+}

+ 113 - 724
sites/all/modules/contrib/admin/print/print.module

@@ -1,31 +1,5 @@
 <?php
 
-/**
- * @defgroup print Printer, email and PDF versions
- *
- * Welcome to the print module developer's documentation. The interesting
- * functions for themers are those that start with 'theme_'.
- *
- * - Printer-friendly pages
- *   - @link print.module Module main file @endlink
- *   - @link print.admin.inc Settings form @endlink
- *   - @link print.pages.inc HTML generation @endlink
- *   - @link print.install (Un)Install routines @endlink
- *   - @link print.tpl.php Page generation template @endlink
- * - Send by email
- *   - @link print_mail.module Module main file @endlink
- *   - @link print_mail.admin.inc Settings form @endlink
- *   - @link print_mail.inc Mail form and send mail routine @endlink
- *   - @link print_mail.install (Un)Install routines @endlink
- * - PDF version
- *   - @link print_pdf.module Module main file @endlink
- *   - @link print_pdf.admin.inc Settings form @endlink
- *   - @link print_pdf.pages.inc PDF generation @endlink
- *   - @link print_pdf.class.inc Auxiliary PHP5 class @endlink
- *   - @link print_pdf.class_php4.inc Auxiliary PHP4 class @endlink
- *   - @link print_pdf.install (Un)Install routines @endlink
- */
-
 /**
  * @file
  * Displays Printer-friendly versions of Drupal pages.
@@ -36,11 +10,8 @@
  * @ingroup print
  */
 
-define('PRINT_PATH', 'print');
+define('PRINT_VIEW_MODE', 'print');
 
-define('PRINT_HTML_FORMAT', 'html');
-define('PRINT_MAIL_FORMAT', 'mail');
-define('PRINT_PDF_FORMAT', 'pdf');
 define('PRINT_LOGO_OPTIONS_DEFAULT', 1);
 define('PRINT_LOGO_URL_DEFAULT', '');
 define('PRINT_FOOTER_OPTIONS_DEFAULT', 1);
@@ -52,16 +23,10 @@ define('PRINT_URLS_ANCHORS_DEFAULT', 0);
 define('PRINT_COMMENTS_DEFAULT', 0);
 define('PRINT_NEWWINDOW_DEFAULT', 1);
 
-define('PRINT_HTML_LINK_POS_DEFAULT', '{ "link": "link", "block": "block", "help": "help" }');
-define('PRINT_HTML_LINK_TEASER_DEFAULT', 0);
-define('PRINT_HTML_SHOW_LINK_DEFAULT', 1);
-define('PRINT_HTML_NODE_LINK_VISIBILITY_DEFAULT', 0);
-define('PRINT_HTML_NODE_LINK_PAGES_DEFAULT', '');
-define('PRINT_HTML_LINK_CLASS_DEFAULT', 'print-page');
-define('PRINT_HTML_SYS_LINK_VISIBILITY_DEFAULT', 1);
-define('PRINT_HTML_SYS_LINK_PAGES_DEFAULT', '');
-define('PRINT_HTML_LINK_USE_ALIAS_DEFAULT', 0);
-define('PRINT_HTML_BOOK_LINK_DEFAULT', 1);
+define('PRINT_TYPE_URLLIST_DEFAULT', 1);
+define('PRINT_TYPE_SYS_URLLIST_DEFAULT', 0);
+define('PRINT_TYPE_LINK_TEXT_ENABLED_DEFAULT', 0);
+
 define('PRINT_HTML_NEW_WINDOW_DEFAULT', 0);
 define('PRINT_HTML_SENDTOPRINTER_DEFAULT', 0);
 define('PRINT_HTML_WINDOWCLOSE_DEFAULT', 1);
@@ -74,14 +39,29 @@ define('PRINT_ROBOTS_NOINDEX_DEFAULT', 1);
 define('PRINT_ROBOTS_NOFOLLOW_DEFAULT', 1);
 define('PRINT_ROBOTS_NOARCHIVE_DEFAULT', 0);
 
-define('PRINT_TYPE_SHOW_LINK_DEFAULT', 1);
-define('PRINT_TYPE_COMMENT_LINK_DEFAULT', 0);
-define('PRINT_TYPE_URLLIST_DEFAULT', 1);
-define('PRINT_TYPE_SYS_URLLIST_DEFAULT', 0);
+define('PRINT_LIB_PATH', 'sites/all/libraries');
+
+/**
+ * Implements hook_print_link().
+ */
+function print_print_link() {
+  return array(
+    'format' => 'html',
+    'text' => t('Printer-friendly version'),
+    'description' => t('Display a printer-friendly version of this page.'),
+    'path' => 'print',
+    'class' => 'print-page',
+    'icon' => 'print_icon.png',
+    'module' => 'print',
+  );
+}
 
-define('PRINT_ALLOW_NORMAL_LINK', 1);
-define('PRINT_ALLOW_BOOK_LINK', 2);
-define('PRINT_TYPE_FIELDS_WEIGHT', 30);
+/**
+ * Implements hook_print_new_window_alter().
+ */
+function print_print_new_window_alter(&$new_window, $format) {
+  $new_window = variable_get('print_html_new_window', PRINT_HTML_NEW_WINDOW_DEFAULT);
+}
 
 /**
  * Implements hook_permission().
@@ -92,10 +72,6 @@ function print_permission() {
       'title' => t('Administer the module'),
       'description' => t('Perform maintenance tasks for the print module.'),
     ),
-    'node-specific print configuration' => array(
-      'title' => t('Node-specific configuration'),
-      'description' => t('Enable access to the per-node settings.'),
-    ),
     'access print' => array(
       'title' => t('Access the printer-friendly page'),
       'description' => t('View the printer-friendly pages and the links to them in the original pages.'),
@@ -108,12 +84,30 @@ function print_permission() {
  */
 function print_theme() {
   return array(
-    'print_format_link' => array(
-      'variables' => array(),
-    ),
     'print' => array(
-      'variables' => array('print' => array(), 'type' => PRINT_HTML_FORMAT, 'node' => NULL),
+      'variables' => array('node' => NULL, 'query' => NULL, 'format' => '', 'expand_css' => FALSE, 'message' => ''),
       'template' => 'print',
+      'file' => 'print.pages.inc',
+    ),
+    'print_published' => array(
+      'variables' => array(),
+      'file' => 'print.pages.inc',
+    ),
+    'print_breadcrumb' => array(
+      'variables' => array('node' => NULL),
+      'file' => 'print.pages.inc',
+    ),
+    'print_footer' => array(
+      'variables' => array(),
+      'file' => 'print.pages.inc',
+    ),
+    'print_sourceurl' => array(
+      'variables' => array('url' => '', 'node' => NULL, 'cid' => NULL),
+      'file' => 'print.pages.inc',
+    ),
+    'print_url_list' => array(
+      'variables' => array(),
+      'file' => 'print.pages.inc',
     ),
   );
 }
@@ -122,7 +116,7 @@ function print_theme() {
  * Implements hook_preprocess_HOOK().
  */
 function print_preprocess_node(&$variables) {
-  if (($variables['elements']['#view_mode'] == 'print') && isset($variables['elements']['#print_format'])) {
+  if (($variables['elements']['#view_mode'] == PRINT_VIEW_MODE) && isset($variables['elements']['#print_format'])) {
     $type = $variables['elements']['#node']->type;
     $format = $variables['elements']['#print_format'];
     $nid = $variables['elements']['#node']->nid;
@@ -134,61 +128,21 @@ function print_preprocess_node(&$variables) {
   }
 }
 
-/**
- * Implements hook_preprocess_HOOK().
- */
-function print_preprocess_print(&$variables) {
-  static $hooks = NULL;
-  if (!isset($hooks)) {
-    drupal_theme_initialize();
-    $hooks = theme_get_registry();
-  }
-
-  $variables['page']['#show_messages'] = FALSE;
-
-  // Stolen from theme() so that ALL preprocess functions are called
-  $hook = 'page';
-  $info = $hooks[$hook];
-  if (isset($info['preprocess functions']) || isset($info['process functions'])) {
-    foreach (array('preprocess functions', 'process functions') as $phase) {
-      if (!empty($info[$phase])) {
-        foreach ($info[$phase] as $processor_function) {
-          if (function_exists($processor_function)) {
-            // We don't want a poorly behaved process function changing $hook.
-            $hook_clone = $hook;
-            $processor_function($variables, $hook_clone);
-          }
-        }
-      }
-    }
-  }
-
-  $format = $variables['type'];
-  $type = (isset($variables['node']->type)) ? $variables['node']->type : '';
-  $nid = (isset($variables['node']->nid)) ? $variables['node']->nid : '';
-
-  $variables['theme_hook_suggestions'] = array();
-  $variables['theme_hook_suggestions'][] = "print__node__{$type}";
-  $variables['theme_hook_suggestions'][] = "print__node__{$type}__{$nid}";
-  $variables['theme_hook_suggestions'][] = "print__{$format}";
-  $variables['theme_hook_suggestions'][] = "print__{$format}__node__{$type}";
-  $variables['theme_hook_suggestions'][] = "print__{$format}__node__{$type}__{$nid}";
-}
-
 /**
  * Implements hook_menu().
  */
 function print_menu() {
+  $link = print_print_link();
   $items = array();
 
-  $items[PRINT_PATH] = array(
+  $items[$link['path']] = array(
     'title' => 'Printer-friendly',
     'page callback' => 'print_controller_html',
     'access arguments' => array('access print'),
     'type' => MENU_CALLBACK,
     'file' => 'print.pages.inc',
   );
-  $items[PRINT_PATH . '/' . PRINT_PATH] = array(
+  $items[$link['path'] . '/' . $link['path']] = array(
     'access callback' => FALSE,
   );
   $items['admin/config/user-interface/print'] = array(
@@ -204,21 +158,6 @@ function print_menu() {
     'weight' => 1,
     'type' => MENU_DEFAULT_LOCAL_TASK,
   );
-  $items['admin/config/user-interface/print/html/options'] = array(
-    'title' => 'Options',
-    'weight' => 1,
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/config/user-interface/print/html/strings'] = array(
-    'title' => 'Text strings',
-    'description' => 'Override the user-facing strings used in the printer-friendly version.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('print_html_strings_settings'),
-    'access arguments'  => array('administer print'),
-    'weight' => 2,
-    'type' => MENU_LOCAL_TASK,
-    'file' => 'print.admin.inc',
-  );
   $items['admin/config/user-interface/print/common'] = array(
     'title' => 'Settings',
     'description' => 'Settings for the common functionalities for all the print sub-modules.',
@@ -229,123 +168,58 @@ function print_menu() {
     'type' => MENU_LOCAL_TASK,
     'file' => 'print.admin.inc',
   );
-  $items['admin/config/user-interface/print/common/options'] = array(
-    'title' => 'Options',
-    'weight' => 1,
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/config/user-interface/print/common/strings'] = array(
-    'title' => 'Text strings',
-    'description' => 'Override the user-facing strings used by the print module.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('print_main_strings_settings'),
-    'access arguments'  => array('administer print'),
-    'weight' => 2,
-    'type' => MENU_LOCAL_TASK,
-    'file' => 'print.admin.inc',
-  );
 
   return $items;
 }
 
+/**
+ * Implements hook_variable_info().
+ */
+function print_variable_info($options) {
+  $link = print_print_link();
+
+  $variable['print_html_link_text'] = array(
+    'title' => t('Printer-friendly version'),
+    'description' => t('Text used in the link to the printer-friendly version.'),
+    'type' => 'string',
+    'default' => t($link['text']),
+  );
+
+  return $variable;
+}
+
 /**
  * Implements hook_block_info().
  */
 function print_block_info() {
-      $block['print-links']['info'] = t('Printer, email and PDF versions');
-      $block['print-links']['cache'] = DRUPAL_CACHE_PER_PAGE;
-      $block['print-top']['info'] = t('Most printed');
-      $block['print-top']['cache'] = DRUPAL_CACHE_GLOBAL;
-      return $block;
+  $block['print-top']['info'] = t('Most printed');
+  $block['print-top']['cache'] = DRUPAL_CACHE_GLOBAL;
+  return $block;
 }
 
 /**
  * Implements hook_block_view().
  */
 function print_block_view($delta = '') {
-  switch ($delta) {
-    case 'print-links':
-      $nid = preg_replace('!^node/!', '', $_GET['q']);
-      if (ctype_digit($nid)) {
-        $node = node_load($nid);
-        if (!node_access('view', $node)) {
-          // If the user doesn't have access to the node, don't show any links
-          $block['content'] = '';
-          return;
-        }
-      }
-      else {
-        $node = NULL;
-      }
-      $block['content'] = '';
-      foreach (array('html' => 'print', 'mail' => 'print_mail', 'pdf' => 'print_pdf') as $format => $module) {
-        $link_pos = variable_get('print_' . $format . '_link_pos', drupal_json_decode(PRINT_HTML_LINK_POS_DEFAULT));
+  $block = array();
 
-        if (!(empty($link_pos['block']))) {
-          $func = $module . '_insert_link';
-
-          if (function_exists($func)) {
-            $links = $func(NULL, $node);
-            if (!empty($links)) {
-              $block['content'] .= $links;
-            }
-          }
-        }
-      }
-      break;
+  switch ($delta) {
     case 'print-top':
       $block['subject'] = t('Most printed');
       $result = db_query_range("SELECT path FROM {print_page_counter} LEFT JOIN {node} n ON path = CONCAT('node/', n.nid) WHERE status <> 0 OR status IS NULL ORDER BY totalcount DESC", 0, 3)
                   ->fetchAll();
       if (count($result)) {
-        $block['content'] = '<div class="item-list"><ul>';
+        $items = array();
         foreach ($result as $obj) {
-          $block['content'] .= '<li>' . l(_print_get_title($obj->path), $obj->path) . '</li>';
+          $items[] = l(_print_get_title($obj->path), $obj->path);
         }
-        $block['content'] .= '</ul></div>';
+        $block['content'] = theme('item_list', array('items' => $items, 'type' => 'ul'));
       }
       break;
   }
   return $block;
 }
 
-/**
- * Implements hook_node_view_alter().
- */
-function print_node_view_alter(&$build) {
-  if (isset($build['links']['book']['#links']['book_printer'])) {
-    $print_html_book_link = variable_get('print_html_book_link', PRINT_HTML_BOOK_LINK_DEFAULT);
-
-    if ($print_html_book_link) {
-      $print_html_link_pos = variable_get('print_html_link_pos', drupal_json_decode(PRINT_HTML_LINK_POS_DEFAULT));
-
-      if (!empty($print_html_link_pos['link'])) {
-        $format = theme('print_format_link');
-
-        switch ($print_html_book_link) {
-          case 1:
-            $path = $build['links']['book']['#links']['book_printer']['href'];
-            break;
-          case 2:
-            $print_html_link_use_alias = variable_get('print_html_link_use_alias', PRINT_HTML_LINK_USE_ALIAS_DEFAULT);
-            $path = ($print_html_link_use_alias && ($alias = drupal_lookup_path('alias', 'node/' . $build['#node']->nid))) ? $alias : $build['#node']->nid;
-            break;
-        }
-
-        $build['links']['book']['#links']['book_printer'] = array(
-          'href' => PRINT_PATH . '/' . $path,
-          'title' => $format['text'],
-          'attributes' => $format['attributes'],
-          'html' => $format['html'],
-        );
-      }
-      else {
-        unset($build['links']['book']['#links']['book_printer']);
-      }
-    }
-  }
-}
-
 /**
  * Implements hook_help().
  */
@@ -355,203 +229,46 @@ function print_help($path, $arg) {
       // Return a line-break version of the module README
       return _filter_autop(file_get_contents(drupal_get_path('module', 'print') . '/README.txt'));
   }
-
-  $print_html_link_pos = variable_get('print_html_link_pos', drupal_json_decode(PRINT_HTML_LINK_POS_DEFAULT));
-  if (($path !== 'node/%') && !(empty($print_html_link_pos['help']))) {
-    static $output = FALSE;
-
-    if ($output === FALSE) {
-      $output = TRUE;
-
-      $link = print_insert_link();
-      if ($link) {
-        return "<span class='print-syslink'>$link</span>";
-      }
-    }
-  }
-}
-
-/**
- * Implements hook_node_view().
- */
-function print_node_view($node, $view_mode) {
-  $print_html_link_pos = variable_get('print_html_link_pos', drupal_json_decode(PRINT_HTML_LINK_POS_DEFAULT));
-  $print_html_link_use_alias = variable_get('print_html_link_use_alias', PRINT_HTML_LINK_USE_ALIAS_DEFAULT);
-
-  foreach (array('node', 'comment') as $type) {
-    $allowed_type = print_link_allowed(array('type' => $type, 'node' => $node, 'view_mode' => $view_mode));
-    if (($allowed_type === PRINT_ALLOW_NORMAL_LINK) && !isset($node->book) && !empty($print_html_link_pos['link'])) {
-      drupal_add_css(drupal_get_path('module', 'print') . '/css/printlinks.css');
-      $links = array();
-      $format = theme('print_format_link');
-
-      $path = (($print_html_link_use_alias) && ($alias = drupal_lookup_path('alias', 'node/' . $node->nid))) ? $alias : $node->nid;
-
-      $links['print_html'] = array(
-        'href' => PRINT_PATH . '/' . $path,
-        'title' => $format['text'],
-        'attributes' => $format['attributes'],
-        'html' => $format['html'],
-        'query' => print_query_string_encode($_GET, array('q')),
-      );
-
-      $link_content = array(
-        '#theme' => 'links',
-        '#links' => $links,
-        '#attributes' => array('class' => array('links', 'inline')),
-      );
-
-      if ($type == 'node') {
-        $node->content['links']['print_html'] = $link_content;
-      }
-      elseif (($type == 'comment') && isset($node->content['comments']['comments'])) {
-        foreach ($node->content['comments']['comments'] as $cid => $comment) {
-          if (is_numeric($cid)) {
-            $link_content['#links']['print_html']['query']['comment'] = $cid;
-            $node->content['comments']['comments'][$cid]['links']['print_html'] = $link_content;
-          }
-        }
-      }
-    }
-  }
-
-  if ($view_mode == 'full') {
-      // Insert content corner links
-      $node->content['print_links'] = array(
-        '#prefix' => '<span class="print-link">',
-        '#markup' => '',
-        '#suffix' => '</span>',
-        '#weight' => -101,
-      );
-      if (!empty($print_html_link_pos['corner'])) {
-        $node->content['print_links']['#markup'] .= print_insert_link(NULL, $node);
-      }
-  }
-}
-
-/**
- * Implements hook_node_load().
- */
-function print_node_load($nodes, $types) {
-  $ids = array();
-  foreach ($nodes as $node) {
-    $ids[] = $node->nid;
-  }
-
-  $result = db_query('SELECT nid, link, comments, url_list FROM {print_node_conf} WHERE nid IN (:nids)', array(':nids' => $ids))->fetchAllAssoc('nid');
-
-  foreach ($nodes as $node) {
-    $node->print_display = isset($result[$node->nid]) ? intval($result[$node->nid]->link) : variable_get('print_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-    $node->print_display_comment = isset($result[$node->nid]) ? intval($result[$node->nid]->comments) : variable_get('print_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-    $node->print_display_urllist = isset($result[$node->nid]) ? intval($result[$node->nid]->url_list) : variable_get('print_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-  }
-}
-
-/**
- * Implements hook_node_insert().
- */
-function print_node_insert($node) {
-  if (user_access('administer print') || user_access('node-specific print configuration')) {
-    if (!isset($node->print_display)) $node->print_display = variable_get('print_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-    if (!isset($node->print_display_comment)) $node->print_display_comment = variable_get('print_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-    if (!isset($node->print_display_urllist)) $node->print_display_urllist = variable_get('print_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-
-    _print_node_conf_modify($node->nid, $node->print_display, $node->print_display_comment, $node->print_display_urllist);
-  }
-}
-
-/**
- * Implements hook_node_update().
- */
-function print_node_update($node) {
-  if (user_access('administer print') || user_access('node-specific print configuration')) {
-    if (!isset($node->print_display)) $node->print_display = variable_get('print_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-    if (!isset($node->print_display_comment)) $node->print_display_comment = variable_get('print_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-    if (!isset($node->print_display_urllist)) $node->print_display_urllist = variable_get('print_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-
-    _print_node_conf_modify($node->nid, $node->print_display, $node->print_display_comment, $node->print_display_urllist);
-  }
 }
 
 /**
  * Implements hook_node_delete().
  */
 function print_node_delete($node) {
-  db_delete('print_node_conf')
-    ->condition('nid', $node->nid)
-    ->execute();
   db_delete('print_page_counter')
     ->condition('path', 'node/' . $node->nid)
     ->execute();
 }
 
-/**
- * Implements hook_form_alter().
- */
-function print_form_alter(&$form, &$form_state, $form_id) {
-  // Add the node-type settings option to activate the printer-friendly version link
-  if ((user_access('administer print') || user_access('node-specific print configuration')) &&
-      (($form_id == 'node_type_form') || !empty($form['#node_edit_form']))) {
-    $form['print'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Printer, email and PDF versions'),
-      '#collapsible' => TRUE,
-      '#collapsed' => TRUE,
-      '#weight' => PRINT_TYPE_FIELDS_WEIGHT,
-      '#group' => 'additional_settings',
-    );
-
-    $form['print']['label'] = array(
-      '#type' => 'markup',
-      '#markup' => '<p><strong>' . t('Printer-friendly version') . '</strong></p>',
-    );
-
-    $form['print']['print_display'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show link'),
-    );
-    $form['print']['print_display_comment'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show link in individual comments'),
-    );
-    $form['print']['print_display_urllist'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show Printer-friendly URLs list'),
-    );
-
-    if ($form_id == 'node_type_form') {
-      $form['print']['print_display']['#default_value'] = variable_get('print_display_' . $form['#node_type']->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-      $form['print']['print_display_comment']['#default_value'] = variable_get('print_display_comment_' . $form['#node_type']->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-      $form['print']['print_display_urllist']['#default_value'] = variable_get('print_display_urllist_' . $form['#node_type']->type, PRINT_TYPE_URLLIST_DEFAULT);
-    }
-    else {
-      $node = $form['#node'];
-      $form['print']['print_display']['#default_value'] = isset($node->print_display) ? $node->print_display : variable_get('print_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-      $form['print']['print_display_comment']['#default_value'] = isset($node->print_display_comment) ? $node->print_display_comment : variable_get('print_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-      $form['print']['print_display_urllist']['#default_value'] = isset($node->print_display_urllist) ? $node->print_display_urllist : variable_get('print_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-    }
-  }
-}
-
 /**
  * Implements hook_entity_info_alter().
  */
 function print_entity_info_alter(&$info) {
   // Add the 'Print' view mode for nodes.
   $info['node']['view modes'] += array(
-    'print' => array(
+    PRINT_VIEW_MODE => array(
       'label' => t('Print'),
-      'custom settings' => TRUE,
+      'custom settings' => FALSE,
     ),
   );
+  // Add the 'Print' view mode for field_collections
+  if (module_exists('field_collection')) {
+    $info['field_collection_item']['view modes'] += array(
+      PRINT_VIEW_MODE => array(
+        'label' => t('Print'),
+        'custom settings' => FALSE,
+      ),
+    );
+  }
 }
 
 /**
  * Auxiliary function to discover a given page's title
  *
- * @param $path
+ * @param string $path
  *   path of the page being identified
- * @return
+ *
+ * @return string
  *   string with the page's title
  */
 function _print_get_title($path) {
@@ -578,338 +295,47 @@ function _print_get_title($path) {
   }
 }
 
-/**
- * Modify the print_node_conf_table
- *
- * Update the print_node_conf table to reflect the given attributes.
- * If updating to the default values, delete the record.
- *
- * @param $nid
- *   value of the nid field (primary key)
- * @param $link
- *   value of the link field (0 or 1)
- * @param $comments
- *   value of the comments field (0 or 1)
- * @param $url_list
- *   value of the url_list field (0 or 1)
- */
-function _print_node_conf_modify($nid, $link, $comments, $url_list) {
-    db_merge('print_node_conf')
-      ->key(array('nid' => $nid))
-      ->fields(array(
-        'link' => $link,
-        'comments' => $comments,
-        'url_list' => $url_list,
-      ))
-      ->execute();
-}
-
-/**
- * Auxiliary function to fill the Printer-friendly link attributes
- *
- * @param $title
- *   text to displayed by the link when hovering over it with the mouse
- * @param $class
- *   class attribute to be used in the link
- * @param $new_window
- *   if TRUE opens the target page in a new window
- * @return
- *   array of formatted attributes
- */
-function print_fill_attributes($title = '', $class = '', $new_window = FALSE) {
-  $print_newwindow = variable_get('print_newwindow', PRINT_NEWWINDOW_DEFAULT);
-  $print_robots_noindex = variable_get('print_robots_noindex', PRINT_ROBOTS_NOINDEX_DEFAULT);
-
-  $attributes = array();
-  $attributes['title'] = $title;
-  if (!empty($class)) {
-    $attributes['class'] = array($class);
-  }
-
-  if ($new_window) {
-    switch ($print_newwindow) {
-    case 0:
-      $attributes['target'] = '_blank';
-      break;
-    case 1:
-      $attributes['onclick'] = 'window.open(this.href); return false';
-      break;
-    }
-  }
-  if (!empty($print_robots_noindex)) {
-    $attributes['rel'] = 'nofollow';
-  }
-  return $attributes;
-}
-
-/**
- * Auxiliary function to set the link text and html flag
- *
- * @param $type
- *   type of link: 0 or 1 for a text-only link, 2 for icon-only and 3 for
- *   both text and icon
- * @param $text
- *   text to be displayed on the link to the printer-friendly page
- * @param $img
- *   path to the icon file
- * @return
- *   array with the link text and html flag
- */
-function _print_format_link_aux($type = 0, $text = '', $img = '') {
-  if ($type >= 2) {
-    $html = TRUE;
-    switch ($type) {
-    case 2:
-      $text = theme('image', array('path' => $img, 'alt' => $text, 'title' => $text, 'attributes' => array('class' => array('print-icon'))));
-      break;
-    case 3:
-      $text = theme('image', array('path' => $img, 'alt' => $text, 'title' => $text, 'attributes' => array('class' => array('print-icon', 'print-icon-margin')))) . $text;
-      break;
-    }
-  }
-  else {
-    $html = FALSE;
-  }
-
-  return array('text' => $text,
-               'html' => $html,
-              );
-}
-
-/**
- * Format the Printer-friendly link
- *
- * @return
- *   array of formatted attributes
- * @ingroup themeable
- */
-function theme_print_format_link() {
-  $print_html_link_class = variable_get('print_html_link_class', PRINT_HTML_LINK_CLASS_DEFAULT);
-  $print_html_new_window = variable_get('print_html_new_window', PRINT_HTML_NEW_WINDOW_DEFAULT);
-  $print_html_show_link = variable_get('print_html_show_link', PRINT_HTML_SHOW_LINK_DEFAULT);
-  $print_html_link_text = filter_xss(variable_get('print_html_link_text', t('Printer-friendly version')));
-
-  $img = drupal_get_path('module', 'print') . '/icons/print_icon.gif';
-  $title = t('Display a printer-friendly version of this page.');
-  $class = strip_tags($print_html_link_class);
-  $new_window = $print_html_new_window;
-  $format = _print_format_link_aux($print_html_show_link, $print_html_link_text, $img);
-
-  return array('text' => $format['text'],
-               'html' => $format['html'],
-               'attributes' => print_fill_attributes($title, $class, $new_window),
-              );
-}
-
 /**
  * Auxiliary function to display a formatted Printer-friendly link
  *
  * Function made available so that developers may call this function from
  * their defined pages/blocks.
  *
- * @param $path
- *   path of the original page (optional). If not specified, the current URL
- *   is used
- * @param $node
- *   an optional node object, to be used in defining the path, if used, the
- *   path argument is irrelevant
- * @return
- *   string with the HTML link to the printer-friendly page
- */
-function print_insert_link($path = NULL, $node = NULL) {
-  if ($node !== NULL) {
-    $nid = $node->nid;
-    $path = 'node/' . $nid;
-    $allowed_type = print_link_allowed(array('node' => $node));
-  }
-  else {
-    if ($path === NULL) {
-      $nid = preg_replace('!^node/([\d]+)!', '$1', $_GET['q']);
-      $path = $_GET['q'];
-    }
-    else {
-      $nid = NULL;
-    }
-    $allowed_type = print_link_allowed(array('path' => $path));
-  }
-
-  if ($allowed_type) {
-    if ($nid !== NULL) {
-      if ($allowed_type === PRINT_ALLOW_BOOK_LINK) {
-        $path = 'book/export/html/' . $nid;
-      }
-      else {
-        if (variable_get('print_html_link_use_alias', PRINT_HTML_LINK_USE_ALIAS_DEFAULT) && ($alias = drupal_lookup_path('alias', $path))) {
-          $path = $alias;
-        }
-        else {
-          $path = $nid;
-        }
-      }
-      $path = PRINT_PATH . '/' . $path;
-      $query = print_query_string_encode($_GET, array('q'));
-    }
-    else {
-      $query = NULL;
-    }
-    drupal_add_css(drupal_get_path('module', 'print') . '/css/printlinks.css');
-    $format = theme('print_format_link');
-    return '<span class="print_html">' . l($format['text'], $path, array('attributes' => $format['attributes'], 'query' => $query, 'absolute' => TRUE, 'html' => $format['html'])) . '</span>';
-  }
-  else {
-    return FALSE;
-  }
-}
-
-/**
- * Check if the provided page is enabled according to the visibility settings
+ * @param string $path
+ *   path to be used in the link. If not specified, the current URL is used.
+ * @param object $node
+ *   node object, to be used in checking node access. If the path argument is
+ *   not provided, the path used will be node/nid.
+ * @param string $location
+ *   where in the page where the link is being inserted ('link', 'corner',
+ *   'block', 'help').
+ *
+ * @return string
+ *   HTML link to the printer-friendly page
  *
- * @param $visibility
- *   current visibility settings:
- *    0 for show on every page except the listed pages
- *    1 for show on only the listed pages
- * @param $pages
- *   list of pages
- * @return
- *   TRUE if it is enabled, FALSE otherwise
+ * @ingroup print_api
  */
-function _print_page_match($visibility, $path, $pages) {
-  if ($pages) {
-    if ($visibility == 2) {
-      if (module_exists('php')) {
-        return php_eval($pages);
-      }
-      else {
-        return FALSE;
-      }
-    }
-    $alias = drupal_get_path_alias($path);
-    $page_match = drupal_match_path($path, $pages);
-    if ($alias != $path) {
-      $page_match = $page_match || drupal_match_path($alias, $pages);
-    }
-
-    return !($visibility xor $page_match);
+function print_insert_link($path = NULL, $node = NULL, $location = '') {
+  if (function_exists('print_ui_insert_link')) {
+    return print_ui_insert_link(print_print_link(), array('path' => $path, 'node' => $node, 'location' => $location));
   }
   else {
-    return !$visibility;
+    return FALSE;
   }
 }
 
 /**
  * Check if the link to the PF version is allowed depending on the settings
  *
- * @param $args
+ * @param array $args
  *   array containing the possible parameters:
- *    teaser, node, type, path
- * @return
- *   FALSE if not allowed
- *   PRINT_ALLOW_NORMAL_LINK if a normal link is allowed
- *   PRINT_ALLOW_BOOK_LINK if a link is allowed in a book node
- */
-function print_link_allowed($args) {
-  $view_mode = isset($args['view_mode']) ? $args['view_mode'] : '';
-  if ((($view_mode == 'teaser') && !variable_get('print_html_link_teaser', PRINT_HTML_LINK_TEASER_DEFAULT))
-      || !in_array($view_mode, array('full', 'teaser', '')) || !user_access('access print')) {
-    // If the teaser link is disabled or the user is not allowed
-    return FALSE;
-  }
-  if (!empty($args['path'])) {
-    $nid = preg_replace('!^node/!', '', drupal_get_normal_path($args['path']));
-    if (ctype_digit($nid)) {
-      $args['node'] = node_load($nid);
-    }
-  }
-  if (!empty($args['node'])) {
-    static $node_type = '';
-
-    $node = $args['node'];
-    if (isset($node->type)) {
-      $node_type = $node->type;
-    }
-    // Node
-    $print_html_node_link_visibility = variable_get('print_html_node_link_visibility', PRINT_HTML_NODE_LINK_VISIBILITY_DEFAULT);
-    $print_html_node_link_pages = variable_get('print_html_node_link_pages', PRINT_HTML_NODE_LINK_PAGES_DEFAULT);
-
-    if (!_print_page_match($print_html_node_link_visibility, "node/" . $node->nid, $print_html_node_link_pages)) {
-      // Page not in visibility list
-      return FALSE;
-    }
-    elseif (isset($args['type']) && ($args['type'] == 'comment') && isset($node_type)) {
-      // Link is for a comment, return the configured setting
-      // Cache this statically to avoid duplicate queries for every comment.
-      static $res = array();
-      if (!isset($res[$node->nid])) {
-        $res[$node->nid] = db_query("SELECT comments FROM {print_node_conf} WHERE nid = :nid", array(':nid' => $node->nid))->fetchField();
-      }
-      $print_display_comment = ($res && ($res[$node->nid] !== FALSE)) ? $res[$node->nid] : variable_get('print_display_comment_' . $node_type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-      if ($print_display_comment) {
-        return PRINT_ALLOW_NORMAL_LINK;
-      }
-    }
-    else {
-      // Node link
-      if (isset($node->print_display) && !$node->print_display) {
-        // Link for this node is disabled
-        return FALSE;
-      }
-      elseif (isset($node->book)) {
-        // Node is a book;
-        $print_html_book_link = variable_get('print_html_book_link', PRINT_HTML_BOOK_LINK_DEFAULT);
-        switch ($print_html_book_link) {
-          case 1:
-            if (user_access('access printer-friendly version')) {
-              return PRINT_ALLOW_BOOK_LINK;
-            }
-            break;
-          case 2:
-            return PRINT_ALLOW_NORMAL_LINK;
-        }
-      }
-      else {
-        return PRINT_ALLOW_NORMAL_LINK;
-      }
-    }
-  }
-  else {
-    // 'System' page
-    $print_html_sys_link_visibility = variable_get('print_html_sys_link_visibility', PRINT_HTML_SYS_LINK_VISIBILITY_DEFAULT);
-    $print_html_sys_link_pages = variable_get('print_html_sys_link_pages', PRINT_HTML_SYS_LINK_PAGES_DEFAULT);
-
-    return _print_page_match($print_html_sys_link_visibility, $_GET['q'], $print_html_sys_link_pages);
-  }
-  return FALSE;
-}
-
-/**
- * Parse an array into a valid urlencoded query string.
- *
- * Modified from drupal_query_string_encode to prevent re-encoding of
- * encoded original. (see #301192)
+ *    view_mode, node, type, path
  *
- * @param $query
- *   The array to be processed e.g. $_GET
- * @param $exclude
- *   The array filled with keys to be excluded.
- * @return
- *   urlencoded string which can be appended to/as the URL query string
+ * @return bool
+ *   FALSE if not allowed, TRUE otherwise
  */
-function print_query_string_encode($query, $exclude = array(), $parent = '') {
-  $params = array();
-  foreach ($query as $key => $value) {
-    if (in_array($key, $exclude, TRUE)) {
-      continue;
-    }
-
-    if (is_array($value)) {
-      $params[$key] = print_query_string_encode($value, $exclude, $key);
-    }
-    else {
-      $params[$key] = $value;
-    }
-  }
-
-  return empty($params) ? NULL : $params;
+function print_link_allowed($args) {
+  return (user_access('access print'));
 }
 
 /**
@@ -922,43 +348,6 @@ function print_contextual_links_view_alter(&$element, $items) {
   }
 }
 
-/**
- * Callback function for the preg_replace_callback replacing spaces with %20
- *
- * Replace spaces in URLs with %20
- *
- * @param array $matches
- *   array with the matched tag patterns, usually <a...>+text+</a>
- *
- * @return string
- *   tag with re-written URL
- */
-function _print_replace_spaces($matches) {
-  // first, split the html into the different tag attributes
-  $pattern = '!\s*(\w+\s*=\s*"(?:\\\"|[^"])*")\s*|\s*(\w+\s*=\s*\'(?:\\\\\'|[^\'])*\')\s*|\s*(\w+\s*=\s*\w+)\s*|\s+!';
-  $attribs = preg_split($pattern, $matches[1], -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
-  foreach ($attribs as $key => $value) {
-    $attribs[$key] = preg_replace('!(\w)\s*=\s*(.*)!', '$1=$2', $value);
-  }
-
-  $size = count($attribs);
-  for ($i=1; $i < $size; $i++) {
-    // If the attribute is href or src, we may need to rewrite the URL in the value
-    if (preg_match('!^(?:href|src)\s*?=(.*)!i', $attribs[$i], $urls) > 0) {
-      $url = trim($urls[1], " \t\n\r\0\x0B\"'");
-      $new_url = str_replace(' ', '%20', $url);
-      $matches[1] = str_replace($url, $new_url, $matches[1]);
-    }
-  }
-
-  $ret = '<' . $matches[1] . '>';
-  if (count($matches) == 4) {
-    $ret .= $matches[2] . $matches[3];
-  }
-
-  return $ret;
-}
-
 /**
  * Implements hook_views_api().
  */

+ 342 - 313
sites/all/modules/contrib/admin/print/print.pages.inc

@@ -22,25 +22,25 @@ function print_controller_html() {
   $args = func_get_args();
   $path = filter_xss(implode('/', $args));
   $cid = isset($_GET['comment']) ? (int)$_GET['comment'] : NULL;
+  $link = print_print_link();
 
-  // Handle the query
-  $query = $_GET;
-  unset($query['q']);
+  $node = print_controller($path, $link['format'], $cid);
+  if ($node) {
+    // Handle the query
+    $query = $_GET;
+    unset($query['q']);
 
-  $print = print_controller($path, $query, $cid, PRINT_HTML_FORMAT);
-  if ($print !== FALSE) {
-    $node = $print['node'];
-    $html = theme('print', array('print' => $print, 'type' => PRINT_HTML_FORMAT, 'node' => $node));
+    $html = theme('print', array('node' => $node, 'query' => $query, 'format' => $link['format']));
     drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
     drupal_send_headers();
     print $html;
 
-    $nodepath = (isset($node->path) && is_string($node->path)) ? drupal_get_normal_path($node->path) : 'node/' . $path;
+    $nodepath = (isset($node->nid)) ? 'node/' . $node->nid : drupal_get_normal_path($path);
     db_merge('print_page_counter')
       ->key(array('path' => $nodepath))
       ->fields(array(
-          'totalcount' => 1,
-          'timestamp' => REQUEST_TIME,
+        'totalcount' => 1,
+        'timestamp' => REQUEST_TIME,
       ))
       ->expression('totalcount', 'totalcount + 1')
       ->execute();
@@ -53,26 +53,24 @@ function print_controller_html() {
  * Depending on the type of node, this functions chooses the appropriate
  * generator function.
  *
- * @param $path
+ * @param string $path
  *   path of the original page
- * @param array $query
- *   (optional) array of key/value pairs as used in the url() function for the
- *   query
- * @param $cid
- *   comment ID of the individual comment to be rendered
- * @param $format
+ * @param string $format
  *   format of the page being generated
- * @param $teaser
- *   if set to TRUE, outputs only the node's teaser
- * @param $message
- *   optional sender's message (used by the send email module)
- * @return
- *   array with the fields to be used in the template
+ * @param int $cid
+ *   comment ID of the individual comment to be rendered
+ * @param string $view_mode
+ *   (optional) view mode to be used when rendering the content
+ *
+ * @return object
+ *   node-like object to be used in the print template
+ *
  * @see _print_generate_node()
  * @see _print_generate_path()
  * @see _print_generate_book()
+ * @see print_preprocess_print()
  */
-function print_controller($path, $query = NULL, $cid = NULL, $format = PRINT_HTML_FORMAT, $teaser = FALSE, $message = NULL) {
+function print_controller($path, $format, $cid = NULL, $view_mode = PRINT_VIEW_MODE) {
   if (empty($path)) {
     // If no path was provided, let's try to generate a page for the referer
     global $base_url;
@@ -93,113 +91,301 @@ function print_controller($path, $query = NULL, $cid = NULL, $format = PRINT_HTM
     array_shift($parts);
     $path = implode('/', $parts);
   }
-  if (ctype_digit($parts[0]) && (count($parts) == 1)) {
-    $print = _print_generate_node($path, $query, $cid, $format, $teaser, $message);
+  $revision_view = preg_match('!^[\d]*/revisions/[\d]*/view$!', $path);
+  if (ctype_digit($parts[0]) && ((count($parts) == 1) || $revision_view)) {
+    $vid = $revision_view ? $parts[2] : NULL;
+    $node = _print_generate_node($path, $format, $vid, $cid, $view_mode);
   }
   else {
     $ret = preg_match('!^book/export/html/(.*)!i', $path, $matches);
     if ($ret == 1) {
       // This is a book PF page link, handle trough the book handling functions
-      $print = _print_generate_book($matches[1], $query, $format, $teaser, $message);
+      $node = _print_generate_book($matches[1], $format);
     }
     else {
       // If no content node was found, handle the page printing with the 'printable' engine
-      $print = _print_generate_path($path, $query, $format, $teaser, $message);
+      $node = _print_generate_path($path, $format);
+    }
+  }
+
+  return $node;
+}
+
+/**
+ * Implements hook_preprocess_HOOK().
+ */
+function print_preprocess_print(&$variables) {
+  global $language;
+
+  $node = $variables['node'];
+  $format = $variables['format'];
+  $path = drupal_get_path_alias(empty($node->nid) ? $node->path : "node/$node->nid");
+
+  static $hooks = NULL;
+  if (!isset($hooks)) {
+    drupal_theme_initialize();
+    $hooks = theme_get_registry();
+  }
+
+  $variables['page']['#show_messages'] = FALSE;
+
+  // Stolen from theme() so that ALL preprocess functions are called
+  $hook = 'page';
+  $info = $hooks[$hook];
+  if (isset($info['preprocess functions']) || isset($info['process functions'])) {
+    $variables['theme_hook_suggestions'] = array();
+    foreach (array('preprocess functions', 'process functions') as $phase) {
+      if (!empty($info[$phase])) {
+        foreach ($info[$phase] as $processor_function) {
+          if (function_exists($processor_function)) {
+            // We don't want a poorly behaved process function changing $hook.
+            $hook_clone = $hook;
+            $processor_function($variables, $hook_clone);
+          }
+        }
+      }
+    }
+  }
+
+  $logo_url = FALSE;
+  switch (variable_get('print_logo_options', PRINT_LOGO_OPTIONS_DEFAULT)) {
+    case 1: // theme's
+      $logo_url = theme_get_setting('logo');
+      break;
+    case 2: // user-specifed
+      $logo_url = strip_tags(variable_get('print_logo_url', PRINT_LOGO_URL_DEFAULT));
+      break;
+  }
+  $logo_url = preg_replace('!^' . base_path() . '!', '', $logo_url);
+
+  $variables['print_logo']                     = $logo_url ? theme('image', array('path' => $logo_url, 'alt' => variable_get('site_name', 'Drupal'), 'attributes' => array('class' => 'print-logo', 'id' => 'logo'))) : NULL;
+
+  $variables['print_node']                     = $node;
+  $variables['content']                  = $node->content;
+  $variables['scripts']                  = drupal_get_js();
+  $variables['footer_scripts']           = drupal_get_js('footer');
+  $variables['sourceurl_enabled']        = variable_get('print_sourceurl_enabled', PRINT_SOURCEURL_ENABLED_DEFAULT);
+  $variables['url']                      = url($path, array('absolute' => TRUE, 'query' => $variables['query']));
+  $variables['source_url']               = url(variable_get('print_sourceurl_forcenode', PRINT_SOURCEURL_FORCENODE_DEFAULT) ? drupal_get_normal_path($path) : $path, array('alias' => TRUE, 'absolute' => TRUE, 'query' => $variables['query']));
+  $variables['cid']                      = isset($node->cid) ? $node->cid : NULL;
+  $variables['print_title']                    = check_plain($node->title);
+  $variables['head']                     = drupal_get_html_head();
+  $variables['robots_meta']              = _print_robots_meta_generator();
+  $variables['css']                      = _print_css_generator($variables['expand_css']);
+
+  if (variable_get('print_html_sendtoprinter', PRINT_HTML_SENDTOPRINTER_DEFAULT) && ($format == 'html')) {
+    drupal_add_js('misc/drupal.js', array('weight' => JS_LIBRARY));
+
+    $window_close = (variable_get('print_html_new_window', PRINT_HTML_NEW_WINDOW_DEFAULT) && variable_get('print_html_windowclose', PRINT_HTML_WINDOWCLOSE_DEFAULT)) ? 'window.close();' : '';
+    $variables['sendtoprinter'] = '<script type="text/javascript">(function ($) { Drupal.behaviors.print = {attach: function(context) {$(window).load(function() {window.print();' . $window_close . '})}}})(jQuery);</script>';
+  }
+
+  $type = (isset($node->type)) ? $node->type : '';
+  $nid = (isset($node->nid)) ? $node->nid : '';
+
+  $variables['theme_hook_suggestions'] = array();
+  $variables['theme_hook_suggestions'][] = "print__node__{$type}";
+  $variables['theme_hook_suggestions'][] = "print__node__{$type}__{$nid}";
+  $variables['theme_hook_suggestions'][] = "print__{$format}";
+  $variables['theme_hook_suggestions'][] = "print__{$format}__node__{$type}";
+  $variables['theme_hook_suggestions'][] = "print__{$format}__node__{$type}__{$nid}";
+}
+
+/**
+ * Returns HTML for the published line of the print template.
+ *
+ * @param array $vars
+ *   An empty associative array
+ *
+ * @return string
+ *   HTML text with the published line
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_published($vars) {
+  global $base_url;
+
+  $published_site = variable_get('site_name', 0);
+  return $published_site ? t('Published on %site_name', array('%site_name' => $published_site)) . ' (' . l($base_url, $base_url) . ')' : '';
+}
+
+/**
+ * Returns HTML for the breadcrumb line of the print template.
+ *
+ * @param array $vars
+ *   An associative array containing:
+ *   - $node: the node object
+ *
+ * @return string
+ *   HTML text with the breadcrumb
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_breadcrumb($vars) {
+  $node = $vars['node'];
+  $old_path = $_GET['q'];
+
+  $path = empty($node->nid) ? $node->path : "node/$node->nid";
+  menu_set_active_item($path);
+  $breadcrumb = drupal_get_breadcrumb();
+  if (!empty($breadcrumb)) {
+    $breadcrumb[] = menu_get_active_title();
+    menu_set_active_item($old_path);
+    return filter_xss(implode(' > ', $breadcrumb));
+  }
+  else {
+    menu_set_active_item($old_path);
+    return '';
+  }
+}
+
+/**
+ * Returns HTML for the footer of the print template.
+ *
+ * @param array $vars
+ *   An empty associative array
+ *
+ * @return string
+ *   HTML text with the footer
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_footer($vars) {
+  $footer = '';
+
+  switch (variable_get('print_footer_options', PRINT_FOOTER_OPTIONS_DEFAULT)) {
+    case 1: // theme's
+      $footer_blocks = block_get_blocks_by_region('footer');
+      $footer = variable_get('site_footer', FALSE) . "\n" . drupal_render($footer_blocks);
+      break;
+    case 2: // user-specifed
+      $footer = variable_get('print_footer_user', PRINT_FOOTER_USER_DEFAULT);
+      break;
+  }
+  // Delete the contextual links
+  $footer = preg_replace('!\s*<div class="contextual-links-wrapper">.*?</div>!sim', '', $footer);
+
+  return filter_xss_admin($footer);
+}
+
+/**
+ * Returns HTML for the source URL line of the print template.
+ *
+ * @param array $vars
+ *   An associative array containing:
+ *   - $url: the URL to the full node view.
+ *   - $node: the node object.
+ *   - $cid; comment ID of the comment to display.
+ *
+ * @return string
+ *   HTML text with the footer
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_sourceurl($vars) {
+  $sourceurl_date = variable_get('print_sourceurl_date', PRINT_SOURCEURL_DATE_DEFAULT);
+  $url = is_int($vars['cid']) ? $vars['url'] . '#comment-' . $vars['cid'] : $vars['url'];
+
+  $output = '<strong>' . t('Source URL');
+  if ($sourceurl_date && isset($vars['node'])) {
+    $output .= ' (';
+    $date = format_date($vars['node']->changed, 'short');
+
+    $output .= empty($vars['node']->nid) ? t('retrieved on !date', array('!date' => $date)) : t('modified on !date', array('!date' => $date));
+
+    $output .= ')';
+  }
+  $output .= ':</strong> ' . $url;
+
+  return $output;
+}
+
+/**
+ * Returns HTML for the URL list of the print template.
+ *
+ * @param array $vars
+ *   An empty associative array
+ *
+ * @return string
+ *   HTML text with the URL list
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_url_list($vars) {
+  global $_print_urls;
+
+  // Display the collected links at the bottom of the page. Code once taken from Kjartan Mannes' project.module
+  if (!empty($_print_urls)) {
+    $urls = _print_friendly_urls();
+    $max = count($urls);
+    $url_list = '';
+    foreach ($urls as $key => $url) {
+      drupal_alter('print_url_list', $url);
+      $url_list .= '[' . ($key + 1) . '] ' . check_plain($url) . "<br />\n";
+    }
+    if (!empty($url_list)) {
+      return "<p><strong>" . t('Links') . "</strong><br />$url_list</p>";
+    }
+    else {
+      return '';
     }
   }
 
-  return $print;
 }
 
 /**
  * Generates a robots meta tag to tell them what they may index
  *
- * @return
- *   string with the meta robots tag
+ * @return string
+ *   meta robots tag
  */
 function _print_robots_meta_generator() {
-  $print_robots_noindex = variable_get('print_robots_noindex', PRINT_ROBOTS_NOINDEX_DEFAULT);
-  $print_robots_nofollow = variable_get('print_robots_nofollow', PRINT_ROBOTS_NOFOLLOW_DEFAULT);
-  $print_robots_noarchive = variable_get('print_robots_noarchive', PRINT_ROBOTS_NOARCHIVE_DEFAULT);
   $robots_meta = array();
 
-  if (!empty($print_robots_noindex)) {
+  if (variable_get('print_robots_noindex', PRINT_ROBOTS_NOINDEX_DEFAULT)) {
     $robots_meta[] = 'noindex';
   }
-  if (!empty($print_robots_nofollow)) {
+  if (variable_get('print_robots_nofollow', PRINT_ROBOTS_NOFOLLOW_DEFAULT)) {
     $robots_meta[] = 'nofollow';
   }
-  if (!empty($print_robots_noarchive)) {
+  if (variable_get('print_robots_noarchive', PRINT_ROBOTS_NOARCHIVE_DEFAULT)) {
     $robots_meta[] = 'noarchive';
   }
 
   if (count($robots_meta) > 0) {
-    $robots_meta = implode(', ', $robots_meta);
-    $robots_meta = "<meta name='robots' content='$robots_meta' />\n";
+    return '<meta name="robots" content=' . implode(', ', $robots_meta) . ' />';
   }
   else {
-    $robots_meta = '';
+    return '';
   }
-
-  return $robots_meta;
 }
 
 /**
- * Post-processor that fills the array for the template with common details
- *
- * @param $node
- *   generated node with a printer-friendly node body
- * @param array $query
- *   (optional) array of key/value pairs as used in the url() function for the
- *   query
- * @param $message
- *   optional sender's message (used by the send email module)
- * @param $cid
- *   id of current comment being generated (NULL when not generating
- *   an individual comment)
- * @return
- *   array with the fields to be used in the template
+ * Generates the CSS directive to include in the printer-friendly version
+ *
+ * @param bool $expand
+ *   If TRUE, the provided CSS will be expanded, instead of given as a list
+ *   of includes.
+ *
+ * @return string
+ *   applicable CSS
  */
-function _print_var_generator($node, $query = NULL, $message = NULL, $cid = NULL) {
-  global $base_url, $language, $_print_urls;
-
-  $path = empty($node->nid) ? $node->path : "node/$node->nid";
-
-  // print module settings
+function _print_css_generator($expand = FALSE) {
   $print_css = variable_get('print_css', PRINT_CSS_DEFAULT);
-  $print_keep_theme_css = variable_get('print_keep_theme_css', PRINT_KEEP_THEME_CSS_DEFAULT);
-  $print_logo_options = variable_get('print_logo_options', PRINT_LOGO_OPTIONS_DEFAULT);
-  $print_logo_url = variable_get('print_logo_url', PRINT_LOGO_URL_DEFAULT);
-  $print_html_new_window = variable_get('print_html_new_window', PRINT_HTML_NEW_WINDOW_DEFAULT);
-  $print_html_sendtoprinter = variable_get('print_html_sendtoprinter', PRINT_HTML_SENDTOPRINTER_DEFAULT);
-  $print_html_windowclose = variable_get('print_html_windowclose', PRINT_HTML_WINDOWCLOSE_DEFAULT);
-  $print_sourceurl_enabled = variable_get('print_sourceurl_enabled', PRINT_SOURCEURL_ENABLED_DEFAULT);
-  $print_sourceurl_forcenode = variable_get('print_sourceurl_forcenode', PRINT_SOURCEURL_FORCENODE_DEFAULT);
-  $print_sourceurl_date = variable_get('print_sourceurl_date', PRINT_SOURCEURL_DATE_DEFAULT);
-  $print_footer_options = variable_get('print_footer_options', PRINT_FOOTER_OPTIONS_DEFAULT);
-  $print_footer_user = variable_get('print_footer_user', PRINT_FOOTER_USER_DEFAULT);
-
-  $print['language'] = $language->language;
-  $print['title'] = check_plain($node->title);
-  $print['head'] = drupal_get_html_head();
-  if ($print_html_sendtoprinter) {
-    drupal_add_js('misc/drupal.js', array('weight' => JS_LIBRARY));
-  }
-  $print['scripts'] = drupal_get_js();
-  $print['footer_scripts'] = drupal_get_js('footer');
-  $print['robots_meta'] = _print_robots_meta_generator();
-  $print['url'] = url($path, array('absolute' => TRUE, 'query' => $query));
-  $print['base_href'] = "<base href='" . $print['url'] . "' />\n";
-  $print['favicon'] = theme_get_setting('toggle_favicon') ? "<link rel='shortcut icon' href='" . theme_get_setting('favicon') . "' type='image/x-icon' />\n" : '';
 
   if (!empty($print_css)) {
-    drupal_add_css(strtr($print_css, array('%t' => path_to_theme())));
+    drupal_add_css(strtr($print_css, array('%t' => drupal_get_path('theme', variable_get('theme_default')))));
   }
   else {
     drupal_add_css(drupal_get_path('module', 'print') . '/css/print.css');
   }
   $drupal_css = drupal_add_css();
-  if (!$print_keep_theme_css) {
+  if (!variable_get('print_keep_theme_css', PRINT_KEEP_THEME_CSS_DEFAULT)) {
     foreach ($drupal_css as $key => $css_file) {
       if ($css_file['group'] == CSS_THEME) {
       // Unset the theme's CSS
@@ -208,131 +394,33 @@ function _print_var_generator($node, $query = NULL, $message = NULL, $cid = NULL
     }
   }
 
-  // If we are sending a message via email, the CSS must be embedded
-  if (!empty($message)) {
+  // Expand the CSS if requested
+  if ($expand) {
     $style = '';
     $css_files = array_keys($drupal_css);
     foreach ($css_files as $filename) {
-      $res = file_exists($filename) ? file_get_contents($filename, TRUE) : FALSE;
-      if ($res != FALSE) {
-        $style .= $res;
+      if (file_exists($filename)) {
+        $style .= file_get_contents($filename, TRUE);
       }
     }
-    $print['css'] = "<style type='text/css' media='all'>$style</style>\n";
-  }
-  else {
-    $print['css'] = drupal_get_css($drupal_css);
-  }
-
-  $window_close = ($print_html_new_window && $print_html_windowclose) ? 'window.close();' : '';
-  $print['sendtoprinter'] = $print_html_sendtoprinter ? '<script type="text/javascript">(function ($) { Drupal.behaviors.print = {attach: function(context) {$(window).load(function() {window.print();' . $window_close . '})}}})(jQuery);</script>' : '';
-
-  switch ($print_logo_options) {
-    case 0: // none
-      $logo_url = 0;
-      break;
-    case 1: // theme's
-      $logo_url = theme_get_setting('logo');
-      break;
-    case 2: // user-specifed
-      $logo_url = strip_tags($print_logo_url);
-      break;
-  }
-  $logo_url = preg_replace('!^' . base_path() . '!', '', $logo_url);
-  $site_name = variable_get('site_name', 'Drupal');
-  $print['logo'] = $logo_url ? theme('image', array('path' => $logo_url, 'alt' => $site_name, 'attributes' => array('class' => 'print-logo', 'id' => 'logo'))) : '';
-
-  switch ($print_footer_options) {
-    case 0: // none
-      $footer = '';
-      break;
-    case 1: // theme's
-      $footer_blocks = block_get_blocks_by_region('footer');
-      $footer = variable_get('site_footer', FALSE) . "\n" . drupal_render($footer_blocks);
-      break;
-    case 2: // user-specifed
-      $footer = $print_footer_user;
-      break;
-  }
-  $print['footer_message'] = filter_xss_admin($footer);
-
-  $published_site = variable_get('site_name', 0);
-  if ($published_site) {
-    $print_text_published = filter_xss(variable_get('print_text_published', t('Published on %site_name')));
-    $published = t($print_text_published, array('%site_name' => $published_site));
-    $print['site_name'] = $published . ' (' . l($base_url, $base_url) . ')';
-  }
-  else {
-    $print['site_name'] = '';
-  }
-
-  if ($print_sourceurl_enabled == 1) {
-    /* Grab and format the src URL */
-    if (empty($print_sourceurl_forcenode)) {
-      $url = $print['url'];
-    }
-    else {
-      $url = $base_url . '/' . (((bool)variable_get('clean_url', '0')) ? '' : '?q=') . $path;
-    }
-    if (is_int($cid)) {
-      $url .= "#comment-$cid";
-    }
-    $retrieved_date = format_date(REQUEST_TIME, 'short');
-    $print_text_retrieved = filter_xss(variable_get('print_text_retrieved', t('retrieved on %date')));
-    $retrieved = t($print_text_retrieved, array('%date' => $retrieved_date));
-    $print['printdate'] = $print_sourceurl_date ? " ($retrieved)" : '';
-
-    $source_url = filter_xss(variable_get('print_text_source_url', t('Source URL')));
-    $print['source_url'] = '<strong>' . $source_url . $print['printdate'] . ':</strong> ' . l($url, $url);
-  }
-  else {
-    $print['source_url'] = '';
-  }
-
-  $print['type'] = (isset($node->type)) ? $node->type : '';
-
-  menu_set_active_item($path);
-  $breadcrumb = drupal_get_breadcrumb();
-  if (!empty($breadcrumb)) {
-    $breadcrumb[] = menu_get_active_title();
-    $print['breadcrumb'] = filter_xss(implode(' > ', $breadcrumb));
+    return "<style type='text/css' media='all'>$style</style>\n";
   }
   else {
-    $print['breadcrumb'] = '';
+    return drupal_get_css($drupal_css);
   }
-
-  // Display the collected links at the bottom of the page. Code once taken from Kjartan Mannes' project.module
-  $print['pfp_links'] = '';
-  if (!empty($_print_urls)) {
-    $urls = _print_friendly_urls();
-    $max = count($urls);
-    $pfp_links = '';
-    if ($max) {
-      for ($i = 0; $i < $max; $i++) {
-        $pfp_links .= '[' . ($i + 1) . '] ' . check_plain($urls[$i]) . "<br />\n";
-      }
-      $links = filter_xss(variable_get('print_text_links', t('Links')));
-      $print['pfp_links'] = "<p><strong>$links:</strong><br />$pfp_links</p>";
-    }
-  }
-
-  $print['node'] = $node;
-  $print['message'] = $message;
-
-  return $print;
 }
 
 /**
  * Callback function for the preg_replace_callback for URL-capable patterns
  *
- * Manipulate URLs to make them absolute in the URLs list, and to add a
- * [n] footnote marker.
+ * Manipulate URLs to make them absolute in the URLs list, and add a [n]
+ * footnote marker.
  *
- * @param $matches
+ * @param array $matches
  *   array with the matched tag patterns, usually <a...>+text+</a>
- * @return
- *   tag with re-written URL and when appropriate the [n] index to the
- *   URL list
+ *
+ * @return string
+ *   tag with re-written URL and, if applicable, the [n] index to the URL list
  */
 function _print_rewrite_urls($matches) {
   global $base_url, $base_root, $_print_urls;
@@ -387,7 +475,7 @@ function _print_rewrite_urls($matches) {
           }
           // Because base href is the original page, change the link to
           // still be usable inside the print page
-          $matches[1] = str_replace($url, base_path() . $_GET['q'] . $url, $matches[1]);
+          $matches[1] = str_replace($url, check_plain(base_path() . $_GET['q'] . $url), $matches[1]);
         }
         else {
           // URL is relative, convert it into absolute URL
@@ -416,15 +504,16 @@ function _print_rewrite_urls($matches) {
     }
   }
 
-  return $ret;
+  return filter_xss_admin($ret);
 }
 
 /**
  * Auxiliary function to store the Printer-friendly URLs list as static.
  *
- * @param $url
+ * @param string $url
  *   absolute URL to be inserted in the list
- * @return
+ *
+ * @return array
  *   list of URLs previously stored if $url is 0, or the current count
  *   otherwise.
  */
@@ -448,43 +537,20 @@ function _print_friendly_urls($url = 0) {
 /**
  * Check URL list settings for this node
  *
- * @param node
+ * @param object $node
  *   node object
- * @param $format
+ * @param string $format
  *   format of the page being generated
- * @return
+ *
+ * @return bool
  *   TRUE if URL list should be displayed, FALSE otherwise
  */
-function _print_url_list_enabled($node, $format = PRINT_HTML_FORMAT) {
+function _print_url_list_enabled($node, $format) {
   if (!isset($node->type)) {
-    switch ($format) {
-      case PRINT_HTML_FORMAT:
-        $node_urllist = variable_get('print_display_sys_urllist', PRINT_TYPE_SYS_URLLIST_DEFAULT);
-        break;
-      case PRINT_MAIL_FORMAT:
-        $node_urllist = variable_get('print_mail_display_sys_urllist', PRINT_TYPE_SYS_URLLIST_DEFAULT);
-        break;
-      case PRINT_PDF_FORMAT:
-        $node_urllist = variable_get('print_pdf_display_sys_urllist', PRINT_TYPE_SYS_URLLIST_DEFAULT);
-        break;
-      default:
-        $node_urllist = PRINT_TYPE_SYS_URLLIST_DEFAULT;
-    }
+    $node_urllist = variable_get('print_' . $format . '_display_sys_urllist', PRINT_TYPE_SYS_URLLIST_DEFAULT);
   }
   else {
-    switch ($format) {
-      case PRINT_HTML_FORMAT:
-        $node_urllist = isset($node->print_display_urllist) ? $node->print_display_urllist : variable_get('print_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-        break;
-      case PRINT_MAIL_FORMAT:
-        $node_urllist = isset($node->print_mail_display_urllist) ? $node->print_mail_display_urllist : variable_get('print_mail_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-        break;
-      case PRINT_PDF_FORMAT:
-        $node_urllist = isset($node->print_pdf_display_urllist) ? $node->print_pdf_display_urllist : variable_get('print_pdf_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-        break;
-      default:
-        $node_urllist = PRINT_TYPE_URLLIST_DEFAULT;
-    }
+    $node_urllist = isset($node->{'print_' . $format . '_display_urllist'}) ? $node->{'print_' . $format . '_display_urllist'} : variable_get('print_' . $format . '_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
   }
 
   // Get value of Printer-friendly URLs setting
@@ -494,23 +560,21 @@ function _print_url_list_enabled($node, $format = PRINT_HTML_FORMAT) {
 /**
  * Prepare a Printer-friendly-ready node body for content nodes
  *
- * @param $nid
+ * @param int $nid
  *   node ID of the node to be rendered into a printer-friendly page
- * @param array $query
- *   (optional) array of key/value pairs as used in the url() function for the
- *   query
- * @param $cid
- *   comment ID of the individual comment to be rendered
- * @param $format
+ * @param string $format
  *   format of the page being generated
- * @param $teaser
- *   if set to TRUE, outputs only the node's teaser
- * @param $message
- *   optional sender's message (used by the send email module)
- * @return
- *   filled array ready to be used in the template
+ * @param int $vid
+ *   (optional) revision ID of the node to use
+ * @param int $cid
+ *   (optional) comment ID of the individual comment to be rendered
+ * @param string $view_mode
+ *   (optional) view mode to be used when rendering the content
+ *
+ * @return object
+ *   filled node-like object to be used in the print template
  */
-function _print_generate_node($nid, $query = NULL, $cid = NULL, $format = PRINT_HTML_FORMAT, $teaser = FALSE, $message = NULL) {
+function _print_generate_node($nid, $format, $vid = NULL, $cid = NULL, $view_mode = PRINT_VIEW_MODE) {
   global $_print_urls;
 
   if (!isset($langcode)) {
@@ -518,7 +582,7 @@ function _print_generate_node($nid, $query = NULL, $cid = NULL, $format = PRINT_
   }
 
   // We can take a node id
-  $node = node_load($nid);
+  $node = node_load($nid, $vid);
   if (!$node) {
     // Node not found
     drupal_not_found();
@@ -531,17 +595,6 @@ function _print_generate_node($nid, $query = NULL, $cid = NULL, $format = PRINT_
   }
   drupal_set_title($node->title);
 
-  $view_mode = $teaser ? 'teaser' : 'print';
-
-  // Turn off Pagination by the Paging module
-  unset($node->pages);
-  unset($node->page_count);
-
-  // Make this page a member of the original page's organic group
-  if (function_exists('og_set_group_context') && isset($node->og_groups)) {
-    og_set_group_context($node->og_groups);
-  }
-
   if ($cid === NULL) {
     // Adapted (simplified) version of node_view
     // Render the node content
@@ -549,18 +602,13 @@ function _print_generate_node($nid, $query = NULL, $cid = NULL, $format = PRINT_
 
     // Disable the links area
     unset($node->content['links']);
-    // Disable fivestar widget output
-    unset($node->content['fivestar_widget']);
-    // Disable service links module output
-    unset($node->content['service_links']);
 
     $build = $node->content;
     unset($node->content);
   }
 
-  $print_comments = variable_get('print_comments', PRINT_COMMENTS_DEFAULT);
-
-  if (function_exists('comment_node_page_additions') && (($cid != NULL) || ($print_comments))) {
+  if (function_exists('comment_node_page_additions') &&
+      (($cid != NULL) || (variable_get('print_comments', PRINT_COMMENTS_DEFAULT)))) {
     // Print only the requested comment (or if $cid is NULL, all of them)
 
     $comments = comment_node_page_additions($node);
@@ -609,30 +657,23 @@ function _print_generate_node($nid, $query = NULL, $cid = NULL, $format = PRINT_
   $pattern = '!<(a\s[^>]*?)>(.*?)(</a>)!is';
   $content = preg_replace_callback($pattern, '_print_rewrite_urls', $content);
 
-  $print = _print_var_generator($node, $query, $message, $cid);
-  $print['content'] = $content;
+  $node->content = $content;
 
-  return $print;
+  return $node;
 }
 
 /**
  * Prepare a Printer-friendly-ready node body for non-content pages
  *
- * @param $path
+ * @param string $path
  *   path of the node to be rendered into a printer-friendly page
- * @param array $query
- *   (optional) array of key/value pairs as used in the url() function for the
- *   query
- * @param $format
+ * @param string $format
  *   format of the page being generated
- * @param $teaser
- *   if set to TRUE, outputs only the node's teaser
- * @param $message
- *   optional sender's message (used by the send email module)
- * @return
- *   filled array ready to be used in the template
+ *
+ * @return object
+ *   filled node-like object to be used in the print template
  */
-function _print_generate_path($path, $query = NULL, $format = PRINT_HTML_FORMAT, $teaser = FALSE, $message = NULL) {
+function _print_generate_path($path, $format) {
   global $_print_urls;
 
   // Handle node tabs
@@ -646,13 +687,13 @@ function _print_generate_path($path, $query = NULL, $format = PRINT_HTML_FORMAT,
   menu_set_active_item($path);
   // Adapted from index.php.
   $node = new stdClass();
-  $node->body = menu_execute_active_handler($path, FALSE);
-  if (is_array($node->body)) {
-    $node->body = drupal_render($node->body);
+  $node->content = menu_execute_active_handler($path, FALSE);
+  if (is_array($node->content)) {
+    $node->content = drupal_render($node->content);
   }
 
-  if (is_int($node->body)) {
-    switch ($node->body) {
+  if (is_int($node->content)) {
+    switch ($node->content) {
       case MENU_NOT_FOUND:
         drupal_not_found();
         return FALSE;
@@ -666,43 +707,37 @@ function _print_generate_path($path, $query = NULL, $format = PRINT_HTML_FORMAT,
 
   $node->title = drupal_get_title();
   $node->path = $path;
-  $node->changed = 0;
+  $node->changed = REQUEST_TIME;
 
   // Delete any links area
-  $node->body = preg_replace('!\s*<div class="links">.*?</div>!sim', '', $node->body);
+  $node->content = preg_replace('!\s*<div class="links">.*?</div>!sim', '', $node->content);
+
+  // Delete the contextual links also
+  $node->content = preg_replace('!\s*<div class="contextual-links-wrapper">.*?</div>!sim', '', $node->content);
 
   // Check URL list settings
   $_print_urls = _print_url_list_enabled($node, $format);
 
   // Convert the a href elements
   $pattern = '!<(a\s[^>]*?)>(.*?)(</a>)!is';
-  $node->body = preg_replace_callback($pattern, '_print_rewrite_urls', $node->body);
-
-  $print = _print_var_generator($node, $query, $message);
-  $print['content'] = $node->body;
+  $node->content = preg_replace_callback($pattern, '_print_rewrite_urls', $node->content);
 
-  return $print;
+  return $node;
 }
 
 
 /**
  * Prepare a Printer-friendly-ready node body for book pages
  *
- * @param $nid
+ * @param int $nid
  *   node ID of the node to be rendered into a printer-friendly page
- * @param array $query
- *   (optional) array of key/value pairs as used in the url() function for the
- *   query
- * @param $format
+ * @param string $format
  *   format of the page being generated
- * @param $teaser
- *   if set to TRUE, outputs only the node's teaser
- * @param $message
- *   optional sender's message (used by the send email module)
- * @return
- *   filled array ready to be used in the template
+ *
+ * @return object
+ *   filled node-like object to be used in the print template
  */
-function _print_generate_book($nid, $query = NULL, $format = PRINT_HTML_FORMAT, $teaser = FALSE, $message = NULL) {
+function _print_generate_book($nid, $format) {
   global $_print_urls;
 
   $node = node_load($nid);
@@ -718,20 +753,14 @@ function _print_generate_book($nid, $query = NULL, $format = PRINT_HTML_FORMAT,
   }
 
   $tree = book_menu_subtree_data($node->book);
-  $node->body = book_export_traverse($tree, 'book_node_export');
+  $node->content = book_export_traverse($tree, 'book_node_export');
 
   // Check URL list settings
   $_print_urls = _print_url_list_enabled($node, $format);
 
   // Convert the a href elements
   $pattern = '!<(a\s[^>]*?)>(.*?)(</a>)!is';
-  $node->body = preg_replace_callback($pattern, '_print_rewrite_urls', $node->body);
-
-  $print = _print_var_generator($node, $query, $message);
-  $print['content'] = $node->body;
-
-  // The title is already displayed by the book_recurse, so avoid duplication
-  $print['title'] = '';
+  $node->content = preg_replace_callback($pattern, '_print_rewrite_urls', $node->content);
 
-  return $print;
+  return $node;
 }

+ 95 - 22
sites/all/modules/contrib/admin/print/print.tpl.php

@@ -2,37 +2,110 @@
 
 /**
  * @file
- * Default print module template
+ * Default theme implementation to display a printer-friendly version page.
  *
+ * This file is akin to Drupal's page.tpl.php template. The contents being
+ * displayed are all included in the $content variable, while the rest of the
+ * template focuses on positioning and theming the other page elements.
+ *
+ * All the variables available in the page.tpl.php template should also be
+ * available in this template. In addition to those, the following variables
+ * defined by the print module(s) are available:
+ *
+ * Arguments to the theme call:
+ * - $node: The node object. For node content, this is a normal node object.
+ *   For system-generated pages, this contains usually only the title, path
+ *   and content elements.
+ * - $format: The output format being used ('html' for the Web version, 'mail'
+ *   for the send by email, 'pdf' for the PDF version, etc.).
+ * - $expand_css: TRUE if the CSS used in the file should be provided as text
+ *   instead of a list of @include directives.
+ * - $message: The message included in the send by email version with the
+ *   text provided by the sender of the email.
+ *
+ * Variables created in the preprocess stage:
+ * - $print_logo: the image tag with the configured logo image.
+ * - $content: the rendered HTML of the node content.
+ * - $scripts: the HTML used to include the JavaScript files in the page head.
+ * - $footer_scripts: the HTML  to include the JavaScript files in the page
+ *   footer.
+ * - $sourceurl_enabled: TRUE if the source URL infromation should be
+ *   displayed.
+ * - $url: absolute URL of the original source page.
+ * - $source_url: absolute URL of the original source page, either as an alias
+ *   or as a system path, as configured by the user.
+ * - $cid: comment ID of the node being displayed.
+ * - $print_title: the title of the page.
+ * - $head: HTML contents of the head tag, provided by drupal_get_html_head().
+ * - $robots_meta: meta tag with the configured robots directives.
+ * - $css: the syle tags contaning the list of include directives or the full
+ *   text of the files for inline CSS use.
+ * - $sendtoprinter: depending on configuration, this is the script tag
+ *   including the JavaScript to send the page to the printer and to close the
+ *   window afterwards.
+ *
+ * print[--format][--node--content-type[--nodeid]].tpl.php
+ *
+ * The following suggestions can be used:
+ * 1. print--format--node--content-type--nodeid.tpl.php
+ * 2. print--format--node--content-type.tpl.php
+ * 3. print--format.tpl.php
+ * 4. print--node--content-type--nodeid.tpl.php
+ * 5. print--node--content-type.tpl.php
+ * 6. print.tpl.php
+ *
+ * Where format is the ouput format being used, content-type is the node's
+ * content type and nodeid is the node's identifier (nid).
+ *
+ * @see print_preprocess_print()
+ * @see theme_print_published
+ * @see theme_print_breadcrumb
+ * @see theme_print_footer
+ * @see theme_print_sourceurl
+ * @see theme_print_url_list
+ * @see page.tpl.php
  * @ingroup print
  */
 ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" lang="<?php print $print['language']; ?>" xml:lang="<?php print $print['language']; ?>">
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
+  "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language; ?>" version="XHTML+RDFa 1.0" dir="<?php print $language->dir; ?>">
   <head>
-    <?php print $print['head']; ?>
-    <?php print $print['base_href']; ?>
-    <title><?php print $print['title']; ?></title>
-    <?php print $print['scripts']; ?>
-    <?php print $print['sendtoprinter']; ?>
-    <?php print $print['robots_meta']; ?>
-    <?php print $print['favicon']; ?>
-    <?php print $print['css']; ?>
+    <?php print $head; ?>
+    <base href='<?php print $url ?>' />
+    <title><?php print $print_title; ?></title>
+    <?php print $scripts; ?>
+    <?php if (isset($sendtoprinter)) print $sendtoprinter; ?>
+    <?php print $robots_meta; ?>
+    <?php if (theme_get_setting('toggle_favicon')): ?>
+      <link rel='shortcut icon' href='<?php print theme_get_setting('favicon') ?>' type='image/x-icon' />
+    <?php endif; ?>
+    <?php print $css; ?>
   </head>
   <body>
-    <?php if (!empty($print['message'])) {
-      print '<div class="print-message">'. $print['message'] .'</div><p />';
-    } ?>
-    <div class="print-logo"><?php print $print['logo']; ?></div>
-    <div class="print-site_name"><?php print $print['site_name']; ?></div>
+    <?php if (!empty($message)): ?>
+      <div class="print-message"><?php print $message; ?></div><p />
+    <?php endif; ?>
+    <?php if ($print_logo): ?>
+      <div class="print-logo"><?php print $print_logo; ?></div>
+    <?php endif; ?>
+    <div class="print-site_name"><?php print theme('print_published'); ?></div>
     <p />
-    <div class="print-breadcrumb"><?php print $print['breadcrumb']; ?></div>
+    <div class="print-breadcrumb"><?php print theme('print_breadcrumb', array('node' => $node)); ?></div>
     <hr class="print-hr" />
-    <div class="print-content"><?php print $print['content']; ?></div>
-    <div class="print-footer"><?php print $print['footer_message']; ?></div>
+    <?php if (!isset($node->type)): ?>
+      <h2 class="print-title"><?php print $print_title; ?></h2>
+    <?php endif; ?>
+    <div class="print-content"><?php print $content; ?></div>
+    <div class="print-footer"><?php print theme('print_footer'); ?></div>
     <hr class="print-hr" />
-    <div class="print-source_url"><?php print $print['source_url']; ?></div>
-    <div class="print-links"><?php print $print['pfp_links']; ?></div>
-    <?php print $print['footer_scripts']; ?>
+    <?php if ($sourceurl_enabled): ?>
+      <div class="print-source_url">
+        <?php print theme('print_sourceurl', array('url' => $source_url, 'node' => $node, 'cid' => $cid)); ?>
+      </div>
+    <?php endif; ?>
+    <div class="print-links"><?php print theme('print_url_list'); ?></div>
+    <?php print $footer_scripts; ?>
   </body>
 </html>

BIN
sites/all/modules/contrib/admin/print/print_epub/icons/epub_icon.png


+ 32 - 0
sites/all/modules/contrib/admin/print/print_epub/lib_handlers/print_epub_phpepub/print_epub_phpepub.drush.inc

@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * drush integration for print_epub_phpepub module EPUB libraries download.
+ */
+
+/**
+ * The EPUB project download URL
+ */
+
+// URI to the the latest PHPePub version.. Hardcoded version unfortunately
+define('PHPEPUB_DOWNLOAD_URI', 'https://github.com/Grandt/PHPePub/tarball/2.04');
+
+/**
+ * Implements hook_drush_command().
+ */
+function print_epub_phpepub_drush_epub_libs_alter(&$epub_libs) {
+  $epub_libs['phpepub'] = array(
+    'callback' => '_print_epub_phpepub_drush_download_url',
+  );
+}
+
+/**
+ * Discover the correct URL of the package to download.
+ *
+ * @return string
+ *   URL of the file to download, FALSE if not known
+ */
+function _print_epub_phpepub_drush_download_url() {
+  return PHPEPUB_DOWNLOAD_URI;
+}

+ 12 - 0
sites/all/modules/contrib/admin/print/print_epub/lib_handlers/print_epub_phpepub/print_epub_phpepub.info

@@ -0,0 +1,12 @@
+name = "PHPePub library handler"
+description = "EPUB generation library using PHPePub."
+core = 7.x
+package = "Printer, email and PDF versions"
+dependencies[] = print_epub
+
+; Information added by Drupal.org packaging script on 2014-04-02
+version = "7.x-2.0"
+core = "7.x"
+project = "print"
+datestamp = "1396426766"
+

+ 65 - 0
sites/all/modules/contrib/admin/print/print_epub/lib_handlers/print_epub_phpepub/print_epub_phpepub.module

@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Generate a EPUB for the print_epub module using the PHPePub library.
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_requirements().
+ */
+function print_epub_phpepub_requirements($phase) {
+  $requirements = array();
+  $t = get_t();
+  switch ($phase) {
+    // At runtime, make sure that a EPUB generation tool is selected
+    case 'runtime':
+      $print_epub_epub_tool = variable_get('print_epub_epub_tool', PRINT_EPUB_EPUB_TOOL_DEFAULT);
+
+      if (!empty($print_epub_epub_tool)) {
+        $tool = explode('|', $print_epub_epub_tool);
+
+        if (is_file($tool[1]) && is_readable($tool[1])) {
+          if (basename($tool[1]) == 'EPub.php') {
+            $version = _print_epub_phpepub_version($tool[1]);
+
+            $requirements['print_epub_tool_version'] = array(
+              'title' => $t('Printer, email and EPUB versions - EPUB generation library'),
+              'value' => $t('PHPePub') . ' ' . $version,
+            );
+          }
+        }
+      }
+      break;
+  }
+  return $requirements;
+}
+
+/**
+ * Find out the version of the PHPePub library
+ *
+ * @param string $epub_tool
+ *   Filename of the tool to be analysed.
+ *
+ * @return string
+ *   version number of the library
+ */
+function _print_epub_phpepub_version($epub_tool) {
+  require_once(DRUPAL_ROOT . '/' . $epub_tool);
+
+  return EPub::VERSION;
+}
+
+/**
+ * Implements hook_print_epub_available_libs_alter().
+ */
+function print_epub_phpepub_print_epub_available_libs_alter(&$epub_tools) {
+  module_load_include('inc', 'print', 'includes/print');
+  $tools = _print_scan_libs('phpepub', '!^EPub.php$!');
+
+  foreach ($tools as $tool) {
+    $epub_tools['print_epub_phpepub|' . $tool] = 'PHPePub (' . dirname($tool) . ')';
+  }
+}

+ 48 - 0
sites/all/modules/contrib/admin/print/print_epub/lib_handlers/print_epub_phpepub/print_epub_phpepub.pages.inc

@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Generates the EPUB version using PHPePub
+ *
+ * This file is included by the print_epub_phpepub module and includes the
+ * functions that interface with the PHPePub library
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_print_epub_generate().
+ */
+function print_epub_phpepub_print_epub_generate($html, $meta, $filename = NULL) {
+  global $language, $base_url;
+
+  module_load_include('inc', 'print', 'includes/print');
+
+  $epub_tool = explode('|', variable_get('print_epub_epub_tool', PRINT_EPUB_EPUB_TOOL_DEFAULT));
+  $images_via_file = variable_get('print_epub_images_via_file', PRINT_EPUB_IMAGES_VIA_FILE_DEFAULT);
+
+  require_once(DRUPAL_ROOT . '/' . $epub_tool[1]);
+
+  // Try to use local file access for image files
+  $html = _print_access_images_via_file($html, $images_via_file);
+
+  // set document information
+  $epub = new EPub();
+
+  $epub->setTitle(html_entity_decode($meta['title'], ENT_QUOTES, 'UTF-8'));
+  $epub->setIdentifier($meta['url'], EPub::IDENTIFIER_URI);
+  $epub->setLanguage($language->language);
+  if (isset($meta['name'])) {
+    $epub->setAuthor(strip_tags($meta['name']), strip_tags($meta['name']));
+  }
+  $epub->setPublisher(variable_get('site_name', 'Drupal'), $base_url);
+  $epub->setSourceURL($meta['url']);
+
+  @$epub->addChapter("Chapter", "epub.html", $html, FALSE);
+
+  $epub->finalize(); // Finalize the book, and build the archive.
+
+  // Close and output EPUB document
+  $epub->sendBook(empty($filename) ? 'page' : $filename);
+  return TRUE;
+}

+ 115 - 0
sites/all/modules/contrib/admin/print/print_epub/print_epub.admin.inc

@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * @file
+ * Contains the administrative functions of the EPUB version module.
+ *
+ * This file is included by the EPUB version module, and includes the
+ * settings form.
+ *
+ * @ingroup print
+ */
+
+/**
+ * Form constructor for the EPUB version module settings form.
+ *
+ * @ingroup forms
+ */
+function print_epub_settings() {
+  $epub_tools = array();
+  drupal_alter('print_epub_available_libs', $epub_tools);
+
+  if (!empty($epub_tools)) {
+    $link = print_epub_print_link();
+
+    $current_epub_tool = variable_get('print_epub_epub_tool', PRINT_EPUB_EPUB_TOOL_DEFAULT);
+    $epub_tool_default =  array_key_exists($current_epub_tool, $epub_tools) ? $current_epub_tool : PRINT_EPUB_EPUB_TOOL_DEFAULT;
+
+    $form['settings'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('EPUB options'),
+    );
+
+    $form['settings']['print_epub_epub_tool'] = array(
+      '#type' => 'radios',
+      '#title' => t('EPUB generation tool'),
+      '#options' => $epub_tools,
+      '#default_value' => $epub_tool_default,
+      '#description' => t('This option selects the EPUB generation tool being used by this module to create the EPUB version.'),
+    );
+
+    $form['settings']['print_epub_images_via_file'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Access images via local file access'),
+      '#default_value' => variable_get('print_epub_images_via_file', PRINT_EPUB_IMAGES_VIA_FILE_DEFAULT),
+      '#description' => t("Enabling this option will make the tool use local file access for image files. This option is not recommended to use in conjunction with modules like imagecache which generate the image after it's first accessed. However, it may be necessary in low-end hosting services where the web server is not allowed to open URLs and the user can't modify that configuration setting."),
+    );
+
+    $form['settings']['print_epub_filename'] = array(
+      '#type' => 'textfield',
+      '#title' => t('EPUB filename'),
+      '#default_value' => variable_get('print_epub_filename', PRINT_EPUB_FILENAME_DEFAULT),
+      '#description' => t("If left empty the generated filename defaults to the node's path. Tokens may be used to build the filename (see following list). The .epub extension will be appended automatically."),
+    );
+    if (module_exists('token')) {
+      $form['settings']['print_epub_filename_patterns'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Replacement patterns'),
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+      );
+      $form['settings']['print_epub_filename_patterns']['descriptions'] = array(
+        '#theme' => 'token_tree',
+        '#token_types' => array('node'),
+      );
+    }
+
+    $form['settings']['print_epub_display_sys_urllist'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Printer-friendly URLs list in system pages'),
+      '#default_value' => variable_get('print_epub_display_sys_urllist', PRINT_TYPE_SYS_URLLIST_DEFAULT),
+      '#description' => t('Enabling this option will display a list of printer-friendly destination URLs at the bottom of the page.'),
+    );
+
+    $form['settings']['link_text'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Custom link text'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+    $form['settings']['link_text']['print_epub_link_text_enabled'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable custom link text'),
+      '#default_value' => variable_get('print_epub_link_text_enabled', PRINT_TYPE_LINK_TEXT_ENABLED_DEFAULT),
+    );
+    $form['settings']['link_text']['print_epub_link_text'] = array(
+      '#type' => 'textfield',
+      '#default_value' => variable_get('print_epub_link_text', $link['text']),
+      '#description' => t('Text used in the link to the EPUB version.'),
+    );
+
+    $form['#validate'][] = '_print_epub_settings_validate';
+  }
+  else {
+    variable_set('print_epub_epub_tool', PRINT_EPUB_EPUB_TOOL_DEFAULT);
+
+    $form['settings'] = array(
+      '#type' => 'markup',
+      '#markup' => '<p>' . t("No EPUB generation tool found! Please download a supported PHP EPUB generation tool. Check this module's INSTALL.txt for more details.") . '</p>',
+    );
+  }
+
+  return system_settings_form($form);
+}
+
+/**
+ * Form validation handler for print_epub_settings().
+ *
+ * @see print_epub_settings()
+ * @ingroup forms
+ */
+function _print_epub_settings_validate($form, &$form_state) {
+  if (empty($form_state['values']['print_epub_epub_tool'])) {
+    form_set_error('print_epub_epub_tool', t("No EPUB tool selected"));
+  }
+}

+ 96 - 0
sites/all/modules/contrib/admin/print/print_epub/print_epub.api.php

@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the EPUB version module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Generate a EPUB version of the provided HTML.
+ *
+ * @param string $html
+ *   HTML content of the EPUB
+ * @param array $meta
+ *   Meta information to be used in the EPUB
+ *   - url: original URL
+ *   - name: author's name
+ *   - title: Page title
+ *   - node: node object
+ * @param string $filename
+ *   (optional) Filename of the generated EPUB
+ *
+ * @return
+ *   generated EPUB page, or NULL in case of error
+ *
+ * @see print_epub_controller_html()
+ * @ingroup print_hooks
+ */
+function hook_print_epub_generate($html, $meta, $filename = NULL) {
+  $epub = new EPUB();
+  $epub->writeHTML($html);
+  if ($filename) {
+    $epub->Output($filename);
+    return TRUE;
+  }
+  else {
+    return $epub->Output();
+  }
+}
+
+/**
+ * Alters the list of available EPUB libraries.
+ *
+ * During the configuration of the EPUB library to be used, the module needs
+ * to discover and display the available libraries. This function should use
+ * the internal _print_scan_libs() function which will scan both the module
+ * and the libraries directory in search of the unique file pattern that can
+ * be used to identify the library location.
+ *
+ * @param array $epub_tools
+ *   An associative array using as key the format 'module|path', and as value
+ *   a string describing the discovered library, where:
+ *   - module: the machine name of the module that handles this library.
+ *   - path: the path where the library is installed, relative to DRUPAL_ROOT.
+ *     If the recommended path is used, it begins with sites/all/libraries.
+ *   As a recommendation, the value should contain in parantheses the path
+ *   where the library was found, to allow the user to distinguish between
+ *   multiple install paths of the same library version.
+ *
+ * @ingroup print_hooks
+ */
+function hook_print_epub_available_libs_alter(&$epub_tools) {
+  module_load_include('inc', 'print', 'includes/print');
+  $tools = _print_scan_libs('foo', '!^foo.php$!');
+
+  foreach ($tools as $tool) {
+    $epub_tools['print_epub_foo|' . $tool] = 'foo (' . dirname($tool) . ')';
+  }
+}
+
+/**
+ * Alters the EPUB filename.
+ *
+ * Changes the value of the EPUB filename variable, just before it is used to
+ * create the file. When altering the variable, do not suffix it with the
+ * '.epub' extension, as the module will do that automatically.
+ *
+ * @param string $epub_filename
+ *   current value of the epub_filename variable, after processing tokens and
+ *   any transliteration steps.
+ * @param string $path
+ *   original alias/system path of the page being converted to EPUB.
+ *
+ * @ingroup print_hooks
+ */
+function hook_print_epub_filename_alter(&$epub_filename, &$path) {
+  $epub_filename = 'foo';
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */

+ 65 - 0
sites/all/modules/contrib/admin/print/print_epub/print_epub.drush.inc

@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * drush integration for print_epub module EPUB libraries download.
+ */
+
+/**
+ * Implements hook_drush_command().
+ */
+function print_epub_drush_command() {
+  $items = array();
+
+  $epub_libs = array();
+  drush_command_invoke_all_ref('drush_epub_libs_alter', $epub_libs);
+
+  $items['print-epub-download'] = array(
+    'description' => 'Download and extract a EPUB library.',
+    'arguments' => array(
+      'library' => dt('The EPUB library to download. Available choices: !libs.', array('!libs' => implode(', ', array_keys($epub_libs)))),
+    ),
+    'options' => array(
+      'path' => dt('A path to the download folder. If omitted Drush will use the default location (@path).', array('@path' => 'sites/all/libraries')),
+    ),
+    'aliases' => array('epubdl'),
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_ROOT, // No site or config needed.
+  );
+
+  return $items;
+}
+
+/**
+ * Implements of drush_hook_COMMAND_validate().
+ */
+function drush_print_epub_download_validate($library = NULL) {
+  if (is_null($library)) {
+    $epub_libs = array();
+    drush_command_invoke_all_ref('drush_epub_libs_alter', $epub_libs);
+
+    drush_set_error('DRUSH_EPUBDL_MISSING_ARG', dt("Usage: drush !cmd <library>\nWhere <library> is one of the following: !libs\n\nTry 'drush !cmd --help' for more information.", array('!cmd' => 'print-epub-download', '!libs' => implode(', ', array_keys($epub_libs)))));
+  }
+}
+
+/**
+ * Download and extract EPUB archive.
+ *
+ * @param string $library
+ *   library to download
+ */
+function drush_print_epub_download($library) {
+  $epub_libs = array();
+  drush_command_invoke_all_ref('drush_epub_libs_alter', $epub_libs);
+
+  if (isset($library) && isset($epub_libs[drupal_strtolower($library)])) {
+    $func = $epub_libs[drupal_strtolower($library)]['callback'];
+
+    $download_url = $func();
+    if ($download_url) {
+      _print_drush_download_lib($library, $download_url);
+    }
+  }
+  else {
+    drush_log(dt('Please specify a EPUB library. Available choices: !libs.', array('!libs' => implode(', ', array_keys($epub_libs)))), 'error');
+  }
+}

+ 13 - 0
sites/all/modules/contrib/admin/print/print_epub/print_epub.info

@@ -0,0 +1,13 @@
+name = "EPUB version"
+description = "Adds the capability to export pages as EPUB. Requires an EPUB library and the respective handler module."
+core = 7.x
+package = "Printer, email and PDF versions"
+dependencies[] = print
+configure = admin/config/user-interface/print/epub
+
+; Information added by Drupal.org packaging script on 2014-04-02
+version = "7.x-2.0"
+core = "7.x"
+project = "print"
+datestamp = "1396426766"
+

+ 159 - 0
sites/all/modules/contrib/admin/print/print_epub/print_epub.install

@@ -0,0 +1,159 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the print_epub module.
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_enable().
+ */
+function print_epub_enable() {
+  $t = get_t();
+
+  // Module weight
+  db_update('system')
+    ->fields(array(
+      'weight' => 4,
+    ))
+    ->condition('type', 'module')
+    ->condition('name', 'print_epub')
+    ->execute();
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function print_epub_uninstall() {
+  variable_del('print_epub_display_sys_urllist');
+  variable_del('print_epub_filename');
+  variable_del('print_epub_images_via_file');
+  variable_del('print_epub_link_text');
+  variable_del('print_epub_link_text_enabled');
+  variable_del('print_epub_epub_tool');
+
+  variable_del('print_epub_book_link');
+  variable_del('print_epub_link_class');
+  variable_del('print_epub_link_pos');
+  variable_del('print_epub_link_teaser');
+  variable_del('print_epub_link_use_alias');
+  variable_del('print_epub_show_link');
+  variable_del('print_epub_sys_link_pages');
+  variable_del('print_epub_sys_link_visibility');
+
+  $settings = db_query("SELECT name FROM {variable} WHERE name LIKE 'print\_epub\_display\_%'");
+  foreach ($settings as $variable) {
+    variable_del($variable->name);
+  }
+}
+
+/**
+ * Implements hook_schema().
+ */
+function print_epub_schema() {
+  $schema['print_epub_node_conf'] = array(
+    'description' => 'EPUB version node-specific configuration settings',
+    'fields' => array(
+      'nid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'The {node}.nid of the node.',
+      ),
+      'link' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 1,
+        'size' => 'tiny',
+        'description' => 'Show link',
+      ),
+      'comments' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 1,
+        'size' => 'tiny',
+        'description' => 'Show link in individual comments',
+      ),
+      'url_list' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 1,
+        'size' => 'tiny',
+        'description' => 'Show Printer-friendly URLs list',
+      ),
+    ),
+    'primary key' => array('nid'),
+  );
+
+  $schema['print_epub_page_counter'] = array(
+    'description' => 'EPUB version access counter',
+    'fields' => array(
+      'path' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'description' => 'Page path',
+      ),
+      'totalcount' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'big',
+        'description' => 'Number of page accesses',
+      ),
+      'timestamp' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Last access',
+      ),
+    ),
+    'primary key' => array('path'),
+  );
+
+  return $schema;
+}
+
+/**
+ * Remove hardcoded numeric deltas from all blocks
+ */
+function print_epub_update_7000(&$sandbox) {
+  $renamed_deltas = array(
+    'print_epub' => array(
+      '0' => 'print_epub-top',
+    ),
+  );
+
+  update_fix_d7_block_deltas($sandbox, $renamed_deltas, array());
+
+  if (variable_get('print_epub_filename', '') == '[site-name] - [title] - [mod-yyyy]-[mod-mm]-[mod-dd]') {
+    variable_set('print_epub_filename', '[site:name] - [node:title] - [node:changed:custom:Y-m-d]');
+  }
+}
+
+/**
+ * Enable block and help area links
+ */
+function print_epub_update_7202(&$sandbox) {
+  $link_pos = variable_get('print_epub_link_pos', drupal_json_decode('{ "link": "link", "block": "block", "help": "help" }'));
+  $link_pos['block'] = 'block';
+  $link_pos['help'] = 'help';
+  variable_set('print_epub_link_pos', $link_pos);
+}
+
+/**
+ * Increase size of the path field in the print_epub_page_counter table
+ */
+function print_epub_update_7203(&$sandbox) {
+  db_drop_primary_key('print_epub_page_counter');
+  db_change_field('print_epub_page_counter', 'path', 'path',
+    array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'description' => 'Page path'),
+    array('primary key' => array('path')));
+}

+ 254 - 0
sites/all/modules/contrib/admin/print/print_epub/print_epub.module

@@ -0,0 +1,254 @@
+<?php
+
+/**
+ * @file
+ * Displays Printer-friendly versions of Drupal pages.
+ *
+ * @ingroup print
+ */
+
+define('PRINT_EPUB_EPUB_TOOL_DEFAULT', 0);
+define('PRINT_EPUB_IMAGES_VIA_FILE_DEFAULT', 0);
+define('PRINT_EPUB_FILENAME_DEFAULT', '[site:name] - [node:title] - [node:changed:custom:Y-m-d]');
+
+/**
+ * Implements hook_print_link().
+ */
+function print_epub_print_link() {
+  return array(
+    'format' => 'epub',
+    'text' => t('EPUB version'),
+    'description' => t('Display a EPUB version of this page.'),
+    'path' => 'printepub',
+    'class' => 'print-epub',
+    'icon' => 'epub_icon.png',
+    'module' => 'print_epub',
+  );
+}
+
+/**
+ * Implements hook_permission().
+ */
+function print_epub_permission() {
+  return array(
+    'access EPUB version' => array(
+      'title' => t('Access the EPUB version'),
+      'description' => t('View the EPUB versions and the links to them in the original pages.'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function print_epub_menu() {
+  $link = print_epub_print_link();
+  $items = array();
+
+  $items[$link['path']] = array(
+    'title' => 'Printer-friendly EPUB',
+    'page callback' => 'print_epub_controller',
+    'access arguments' => array('access EPUB version'),
+    'type' => MENU_CALLBACK,
+    'file' => 'print_epub.pages.inc',
+  );
+  $items[$link['path'] . '/' . $link['path']] = array(
+    'access callback' => FALSE,
+  );
+  $items['admin/config/user-interface/print/epub'] = array(
+    'title' => 'EPUB',
+    'description' => 'Configure the settings of the EPUB generation functionality.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('print_epub_settings'),
+    'access arguments'  => array('administer print'),
+    'weight' => 3,
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'print_epub.admin.inc',
+  );
+  $items['admin/config/user-interface/print/epub/options'] = array(
+    'title' => 'Options',
+    'weight' => -1,
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_variable_info().
+ */
+function print_epub_variable_info($options) {
+  $link = print_epub_print_link();
+
+  $variable['print_epub_link_text'] = array(
+    'title' => t('EPUB version'),
+    'description' => t('Text used in the link to the EPUB version.'),
+    'type' => 'string',
+    'default' => t($link['text']),
+  );
+
+  return $variable;
+}
+
+/**
+ * Implements hook_block_info().
+ */
+function print_epub_block_info() {
+  $block['print_epub-top']['info'] = t('Most EPUBed');
+  $block['print_epub-top']['cache'] = DRUPAL_CACHE_GLOBAL;
+  return $block;
+}
+
+/**
+ * Implements hook_block_view().
+ */
+function print_epub_block_view($delta = 0) {
+  switch ($delta) {
+    case 'print_epub-top':
+      $block['subject'] = t('Most EPUBd');
+      $result = db_query_range("SELECT path FROM {print_epub_page_counter} LEFT JOIN {node} n ON path = CONCAT('node/', n.nid) WHERE status <> 0 OR status IS NULL ORDER BY totalcount DESC", 0, 3)
+                  ->fetchAll();
+      if (count($result)) {
+        $items = array();
+        foreach ($result as $obj) {
+          $items[] = l(_print_get_title($obj->path), $obj->path);
+        }
+        $block['content'] = theme('item_list', array('items' => $items, 'type' => 'ul'));
+      }
+      break;
+  }
+  return $block;
+}
+
+/**
+ * Implements hook_requirements().
+ */
+function print_epub_requirements($phase) {
+  $requirements = array();
+  $t = get_t();
+  switch ($phase) {
+    // At runtime, make sure that a EPUB generation tool is selected
+    case 'runtime':
+      $print_epub_epub_tool = variable_get('print_epub_epub_tool', PRINT_EPUB_EPUB_TOOL_DEFAULT);
+      if (empty($print_epub_epub_tool)) {
+        $requirements['print_epub_tool'] = array(
+          'title' => $t('Printer, email and EPUB versions - EPUB generation library'),
+          'value' => $t('No EPUB tool selected'),
+          'description' => $t('Please configure it in the !url.', array('!url' => l($t('EPUB settings page'), 'admin/config/user-interface/print/epub'))),
+          'severity' => REQUIREMENT_ERROR,
+        );
+      }
+      else {
+        $tool = explode('|', $print_epub_epub_tool);
+
+        if (!is_file($tool[1]) || !is_readable($tool[1])) {
+          $requirements['print_epub_tool'] = array(
+            'title' => $t('Printer, email and EPUB versions - EPUB generation library'),
+            'value' => $t('File not found'),
+            'description' => $t('The currently selected EPUB generation library (%file) is no longer accessible.', array('%file' => $tool[1])),
+            'severity' => REQUIREMENT_ERROR,
+          );
+        }
+      }
+      break;
+  }
+  return $requirements;
+}
+
+/**
+ * Implements hook_node_delete().
+ */
+function print_epub_node_delete($node) {
+  db_delete('print_epub_page_counter')
+    ->condition('path', 'node/' . $node->nid)
+    ->execute();
+}
+
+/**
+ * Auxiliary function to display a formatted EPUB version link
+ *
+ * Function made available so that developers may call this function from
+ * their defined pages/blocks.
+ *
+ * @param string $path
+ *   path to be used in the link. If not specified, the current URL is used.
+ * @param object $node
+ *   node object, to be used in checking node access. If the path argument is
+ *   not provided, the path used will be node/nid.
+ * @param string $location
+ *   where in the page where the link is being inserted ('link', 'corner',
+ *   'block', 'help').
+ *
+ * @return bool
+ *   string with the HTML link to the printer-friendly page
+ *
+ * @ingroup print_api
+ */
+function print_epub_insert_link($path = NULL, $node = NULL, $location = '') {
+  if (function_exists('print_ui_insert_link')) {
+    return print_ui_insert_link(print_epub_print_link(), array('path' => $path, 'node' => $node, 'location' => $location));
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Check if the link to the EPUB version is allowed depending on the settings
+ *
+ * @param array $args
+ *   array containing the possible parameters:
+ *    view_mode, node, type, path
+ *
+ * @return bool
+ *   FALSE if not allowed, TRUE otherwise
+ */
+function print_epub_link_allowed($args) {
+  $print_epub_epub_tool = variable_get('print_epub_epub_tool', PRINT_EPUB_EPUB_TOOL_DEFAULT);
+
+  return (user_access('access EPUB version') && (!empty($print_epub_epub_tool)));
+}
+
+/**
+ * Generate a EPUB version of the provided HTML.
+ *
+ * @param string $html
+ *   HTML content of the EPUB
+ * @param array $meta
+ *   Meta information to be used in the EPUB
+ *   - url: original URL
+ *   - name: author's name
+ *   - title: Page title
+ *   - node: node object
+ * @param string $filename
+ *   (optional) Filename of the generated EPUB
+ *
+ * @return
+ *   generated EPUB page, or NULL in case of error
+ *
+ * @see print_epub_controller()
+ *
+ * @ingroup print_api
+ */
+function print_epub_generate_html($html, $meta, $filename = NULL) {
+  $epub_tool = explode('|', variable_get('print_epub_epub_tool', PRINT_EPUB_EPUB_TOOL_DEFAULT));
+
+  module_load_include('inc', $epub_tool[0], $epub_tool[0] . '.pages');
+
+  $function = $epub_tool[0] . '_print_epub_generate';
+  if (function_exists($function)) {
+    return $function($html, $meta, $filename);
+  }
+
+  return NULL;
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function print_epub_views_api() {
+  return array(
+    'api' => 2.0,
+    'path' => drupal_get_path('module', 'print_epub'),
+  );
+}

+ 126 - 0
sites/all/modules/contrib/admin/print/print_epub/print_epub.pages.inc

@@ -0,0 +1,126 @@
+<?php
+
+/**
+ * @file
+ * Generates the EPUB versions of the pages
+ *
+ * This file is included by the print_epub module and includes the
+ * functions that interface with the EPUB generation packages.
+ *
+ * @ingroup print
+ */
+
+module_load_include('inc', 'print', 'print.pages');
+
+/**
+ * Generate a EPUB version of the printer-friendly page
+ *
+ * @see print_controller()
+ * @see _print_epub_domepub()
+ * @see _print_epub_tcepub()
+ */
+function print_epub_controller() {
+  // Disable caching for generated EPUBs, as Drupal doesn't ouput the proper headers from the cache
+  $GLOBALS['conf']['cache'] = FALSE;
+
+  $args = func_get_args();
+  $path = filter_xss(implode('/', $args));
+  $cid = isset($_GET['comment']) ? (int)$_GET['comment'] : NULL;
+
+  // Handle the query
+  $query = $_GET;
+  unset($query['q']);
+
+  if (!empty($path)) {
+    if ($alias = drupal_lookup_path('source', $path)) {
+      // Alias
+      $path_arr = explode('/', $alias);
+      $node = node_load($path_arr[1]);
+    }
+    elseif (ctype_digit($args[0])) {
+      // normal nid
+      $node = node_load($args[0]);
+    }
+
+    $epub_filename = variable_get('print_epub_filename', PRINT_EPUB_FILENAME_DEFAULT);
+    if (!empty($epub_filename) && !empty($node)) {
+      $epub_filename = token_replace($epub_filename, array('node' => $node), array('clear' => TRUE));
+    }
+    else {
+      $epub_filename = token_replace($epub_filename, array('site'), array('clear' => TRUE));
+      if (empty($epub_filename)) {
+        // If empty, use a fallback solution
+        $epub_filename = str_replace('/', '_', $path);
+      }
+    }
+  }
+  else {
+    $epub_filename = 'page';
+  }
+
+  if (function_exists('transliteration_clean_filename')) {
+    $epub_filename = transliteration_clean_filename($epub_filename, language_default('language'));
+  }
+
+  drupal_alter('print_epub_filename', $epub_filename, $path);
+
+  $epub = print_epub_generate_path($path, $query, $cid, $epub_filename . '.epub');
+  if ($epub == NULL) {
+    drupal_goto($path);
+    exit;
+  }
+
+  $nodepath = (isset($node->nid)) ? 'node/' . $node->nid : drupal_get_normal_path($path);
+  db_merge('print_epub_page_counter')
+    ->key(array('path' => $nodepath))
+    ->fields(array(
+        'totalcount' => 1,
+        'timestamp' => REQUEST_TIME,
+    ))
+    ->expression('totalcount', 'totalcount + 1')
+    ->execute();
+
+  drupal_exit();
+}
+
+/**
+ * Gennerate a EPUB for a given Drupal path.
+ *
+ * @param string $path
+ *   path of the page to convert to EPUB
+ * @param array $query
+ *   (optional) array of key/value pairs as used in the url() function for the
+ *   query
+ * @param int $cid
+ *   (optional) comment ID of the comment to render.
+ * @param string $epub_filename
+ *   (optional) filename of the generated EPUB
+ * @param string $view_mode
+ *   (optional) view mode to be used when rendering the content
+ *
+ * @return
+ *   generated EPUB page, or NULL in case of error
+ *
+ * @see print_epub_controller()
+ */
+function print_epub_generate_path($path, $query = NULL, $cid = NULL, $epub_filename = NULL, $view_mode = PRINT_VIEW_MODE) {
+  global $base_url;
+
+  $link = print_epub_print_link();
+  $node = print_controller($path, $link['format'], $cid, $view_mode);
+  if ($node) {
+    $html = theme('print', array('node' => $node, 'query' => $query, 'expand_css' => TRUE, 'format' => $link['format']));
+
+    $meta = array(
+      'node' => $node,
+      'url' => url(drupal_get_path_alias(empty($node->nid) ? $node->path : "node/$node->nid"), array('absolute' => TRUE)),
+    );
+    if (isset($node->name)) $meta['name'] = $node->name;
+    if (isset($node->title)) $meta['title'] = $node->title;
+
+    return print_epub_generate_html($html, $meta, $epub_filename);
+  }
+  else {
+    return NULL;
+  }
+}

+ 121 - 0
sites/all/modules/contrib/admin/print/print_epub/print_epub.views.inc

@@ -0,0 +1,121 @@
+<?php
+
+/**
+ * @file
+ * EPUB Version Views integration
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_views_data().
+ */
+function print_epub_views_data() {
+  // The 'group' index will be used as a prefix in the UI for any of this
+  // table's fields, sort criteria, etc. so it's easy to tell where they came
+  // from.
+  $data['print_epub_node_conf']['table']['group'] = t('Printer-friendly version');
+  $data['print_epub_page_counter']['table']['group'] = t('Printer-friendly version');
+
+  // This table references the {node} table. The declaration below creates an
+  // 'implicit' relationship to the node table, so that when 'node' is the base
+  // table, the fields are automatically available.
+  $data['print_epub_node_conf']['table']['join']['node'] = array(
+    // 'left_field' is the primary key in the referenced table.
+    // 'field' is the foreign key in this table.
+    'left_field' => 'nid',
+    'field' => 'nid',
+//    'type' => 'INNER',
+  );
+  $data['print_epub_page_counter']['table']['join']['node'] = array(
+    // 'left_field' is the primary key in the referenced table.
+    // 'field' is the foreign key in this table.
+    'left_field' => 'nid',
+    'field' => 'path',
+//    'type' => 'INNER',
+    'handler' => 'print_join_page_counter',
+  );
+
+  // print_epub_node_conf fields
+  $data['print_epub_node_conf']['link'] = array(
+    'title' => t('EPUB: Show link'),
+    'help' => t('Whether to show the EPUB version link.'),
+    'field' => array(
+      'handler' => 'views_handler_field_boolean',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_boolean_operator',
+      'label' => t('Active'),
+      'type' => 'yes-no',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['print_epub_node_conf']['comments'] = array(
+    'title' => t('EPUB: Show link in individual comments'),
+    'help' => t('Whether to show the EPUB version link in individual comments.'),
+    'field' => array(
+      'handler' => 'views_handler_field_boolean',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_boolean_operator',
+      'label' => t('Active'),
+      'type' => 'yes-no',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['print_epub_node_conf']['url_list'] = array(
+    'title' => t('EPUB: Show Printer-friendly URLs list'),
+    'help' => t('Whether to show the URL list.'),
+    'field' => array(
+      'handler' => 'views_handler_field_boolean',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_boolean_operator',
+      'label' => t('Active'),
+      'type' => 'yes-no',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
+
+  // print_epub_page_counter fields
+  $data['print_epub_page_counter']['totalcount'] = array(
+    'title' => t('EPUB: Number of page accesses'),
+    'help' => t('Counter of accesses to the EPUB version for this node.'),
+    'field' => array(
+      'handler' => 'views_handler_field_numeric',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    ),
+  );
+  $data['print_epub_page_counter']['timestamp'] = array(
+    'title' => t('EPUB: Last access'),
+    'help' => t("The date of the last access to the node's EPUB version."),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+  );
+
+  return $data;
+}

+ 5 - 3
sites/all/modules/contrib/admin/print/print_join_page_counter.inc

@@ -11,13 +11,15 @@ class print_join_page_counter extends views_join {
   // PHP 4 doesn't call constructors of the base class automatically from a
   // constructor of a derived class. It is your responsibility to propagate
   // the call to constructors upstream where appropriate.
-  function construct($table, $left_table, $left_field, $field, $extra = array(), $type = 'LEFT') {
+  function construct($table = NULL, $left_table = NULL, $left_field = NULL, $field = NULL, $extra = array(), $type = 'LEFT') {
     parent::construct($table, $left_table, $left_field, $field, $extra, $type);
   }
 
   function build_join($select_query, $table, $view_query) {
-    $this->left_field = "CONCAT('node/', " . $this->left_table . '.' . $this->left_field . ')';
-    $this->left_table = NULL;
+    if ($this->left_table) {
+      $this->left_field = "CONCAT('node/', $this->left_table.$this->left_field)";
+      $this->left_table = NULL;
+    }
     parent::build_join($select_query, $table, $view_query);
   }
 }

+ 3 - 0
sites/all/modules/contrib/admin/print/print_mail/css/print_mail.theme-rtl.css

@@ -0,0 +1,3 @@
+label.printmail-label {
+  float: right;
+}

+ 8 - 0
sites/all/modules/contrib/admin/print/print_mail/css/print_mail.theme.css

@@ -0,0 +1,8 @@
+label.printmail-label {
+  width: 175px;
+  float: left;
+}
+
+form#print-mail-form textarea#edit-txt-to-addrs {
+  width: auto;
+}

BIN
sites/all/modules/contrib/admin/print/print_mail/icons/mail_icon.png


+ 21 - 175
sites/all/modules/contrib/admin/print/print_mail/print_mail.admin.inc

@@ -14,123 +14,18 @@
 @include_once('Mail/mime.php');
 
 /**
- * Menu callback for the send by email module settings form.
+ * Form constructor for the send by email module settings form.
  *
  * @ingroup forms
  */
 function print_mail_settings() {
+  $link = print_mail_print_link();
+
   $form['settings'] = array(
     '#type' => 'fieldset',
     '#title' => t('Send by email options'),
   );
 
-  $form['settings']['print_mail_link_pos'] = array(
-    '#type' => 'checkboxes',
-    '#title' => t('Send by email link'),
-    '#default_value' => variable_get('print_mail_link_pos', drupal_json_decode(PRINT_MAIL_LINK_POS_DEFAULT)),
-    '#options' => array('link' => t('Links area'), 'corner' => t('Content corner'), 'block' => t('Block'), 'help' => t('Help area')),
-    '#description' => t('Choose the location of the link(s) to the send by email page. The Links area is usually below the node content, whereas the Content corner is placed in the upper-right corner of the node content. Unselect all options to disable the link. Even if the link is disabled, you can still send a node by email by going to !path/nid where nid is the numeric id of the node.', array('!path' => PRINTMAIL_PATH)),
-  );
-
-  $form['settings']['print_mail_link_teaser'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Display send by email link in teaser'),
-    '#default_value' => variable_get('print_mail_link_teaser', PRINT_MAIL_LINK_TEASER_DEFAULT),
-    '#description' => t('Enabling this will display the link in teaser mode.'),
-  );
-
-  $form['settings']['adv_link'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Advanced link options'),
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-  );
-
-  $form['settings']['adv_link']['print_mail_show_link'] = array(
-    '#type' => 'radios',
-    '#title' => t('Link style'),
-    '#default_value' => variable_get('print_mail_show_link', PRINT_MAIL_SHOW_LINK_DEFAULT),
-    '#options' => array(1 => t('Text only'), 2 => t('Icon only'), 3 => t('Icon and Text')),
-    '#description' => t('Select the visual style of the link.'),
-  );
-
-  $form['settings']['adv_link']['print_mail_link_use_alias'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Use URL alias instead of node ID'),
-    '#default_value' => variable_get('print_mail_link_use_alias', PRINT_MAIL_LINK_USE_ALIAS_DEFAULT),
-    '#description' => t('Enabling this will create the link using the URL alias instead of the node ID.'),
-  );
-
-  $form['settings']['adv_link']['print_mail_link_class'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Link class'),
-    '#default_value' => variable_get('print_mail_link_class', PRINT_MAIL_LINK_CLASS_DEFAULT),
-    '#size' => 60,
-    '#maxlength' => 250,
-    '#description' => t('This can be used by themers to change the link style or by jQuery modules to open in a new window (e.g. greybox or thickbox). Multiple classes can be specified, separated by spaces.'),
-  );
-
-  $form['settings']['adv_link']['print_mail_node_link_visibility'] = array(
-    '#type' => 'radios',
-    '#title' => t('Link visibility'),
-    '#default_value' => variable_get('print_mail_node_link_visibility', PRINT_MAIL_NODE_LINK_VISIBILITY_DEFAULT),
-    '#options' => array(t('Show on every page except the listed pages.'), t('Show on only the listed pages.')),
-  );
-
-  $form['settings']['adv_link']['print_mail_node_link_pages'] = array(
-    '#type' => 'textarea',
-    '#default_value' => variable_get('print_mail_node_link_pages', PRINT_MAIL_NODE_LINK_PAGES_DEFAULT),
-    '#rows' => 3,
-    '#description' => t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>')),
-  );
-
-  if (module_exists('php')) {
-    $access = user_access('use PHP for settings');
-
-    if ($form['settings']['adv_link']['print_mail_node_link_visibility']['#default_value'] == 2 && !$access) {
-      $form['settings']['adv_link']['print_mail_node_link_visibility'] = array('#type' => 'value', '#value' => 2);
-      $form['settings']['adv_link']['print_mail_node_link_pages'] = array('#type' => 'value', '#value' => $form['settings']['adv_link']['print_mail_node_link_pages']['#default_value']);
-    }
-    elseif ($access) {
-      $form['settings']['adv_link']['print_mail_node_link_visibility']['#options'][] = t('Show if the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
-      $form['settings']['adv_link']['print_mail_node_link_pages']['#description'] .= ' ' . t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can break your Drupal site.', array('%php' => '<?php ?>'));
-    }
-  }
-
-  $form['settings']['adv_link']['print_mail_sys_link_visibility'] = array(
-    '#type' => 'radios',
-    '#title' => t('Show link in system (non-content) pages'),
-    '#description' => 'Any page that is not a Drupal node. Usually pages generated by Drupal or a module such as Views or Panels.',
-    '#default_value' => variable_get('print_mail_sys_link_visibility', PRINT_MAIL_SYS_LINK_VISIBILITY_DEFAULT),
-    '#options' => array(t('Show on every page except the listed pages.'), t('Show on only the listed pages.')),
-  );
-
-  $form['settings']['adv_link']['print_mail_sys_link_pages'] = array(
-    '#type' => 'textarea',
-    '#default_value' => variable_get('print_mail_sys_link_pages', PRINT_MAIL_SYS_LINK_PAGES_DEFAULT),
-    '#rows' => 3,
-    '#description' => t('Setting this option will add a send by email link on pages created by Drupal or the enabled modules.') . '<br />' .
-                      t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>')),
-  );
-
-  if (module_exists('php')) {
-    if ($form['settings']['adv_link']['print_mail_sys_link_visibility']['#default_value'] == 2 && !$access) {
-      $form['settings']['adv_link']['print_mail_sys_link_visibility'] = array('#type' => 'value', '#value' => 2);
-      $form['settings']['adv_link']['print_mail_sys_link_pages'] = array('#type' => 'value', '#value' => $form['settings']['adv_link']['print_mail_sys_link_pages']['#default_value']);
-    }
-    elseif ($access) {
-      $form['settings']['adv_link']['print_mail_sys_link_visibility']['#options'][] = t('Show if the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
-      $form['settings']['adv_link']['print_mail_sys_link_pages']['#description'] .= ' ' . t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can break your Drupal site.', array('%php' => '<?php ?>'));
-    }
-  }
-
-  $form['settings']['adv_link']['print_mail_book_link'] = array(
-    '#type' => 'radios',
-    '#title' => t('Link in book hierarchy nodes'),
-    '#default_value' => variable_get('print_mail_book_link', PRINT_MAIL_BOOK_LINK_DEFAULT),
-    '#options' => array(t('No link'), t('Current page and sub-pages'), t('Current page only')),
-  );
-
   $form['settings']['print_mail_hourly_threshold'] = array(
     '#type' => 'select',
     '#title' => t('Hourly threshold'),
@@ -153,6 +48,13 @@ function print_mail_settings() {
     '#description' => t("If selected, the default choice will be to send only the node's teaser instead of the full content."),
   );
 
+  $form['settings']['print_mail_user_recipients'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable user list recipients'),
+    '#default_value' => variable_get('print_mail_user_recipients', PRINT_MAIL_USER_RECIPIENTS_DEFAULT),
+    '#description' => t("If selected, a user list will be included as possible email recipients."),
+  );
+
   $form['settings']['print_mail_teaser_choice'] = array(
     '#type' => 'checkbox',
     '#title' => t('Enable teaser/full mode choice'),
@@ -188,78 +90,22 @@ function print_mail_settings() {
     '#description' => t('Enabling this option will display a list of printer-friendly destination URLs at the bottom of the page.'),
   );
 
-  return system_settings_form($form);
-}
-
-/**
- * Menu callback for the send by email module text strings settings form.
- *
- * @ingroup forms
- */
-function print_mail_strings_settings() {
-  drupal_set_message(t("Saving these strings will disable their translation via Drupal's language system. Use the reset button to return them to the original state."), 'warning', FALSE);
-
-  $form['print_mail_text'] = array(
+  $form['settings']['link_text'] = array(
     '#type' => 'fieldset',
-    '#title' => t('Text strings'),
-  );
-
-  $form['print_mail_text']['print_mail_link_text'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Link text'),
-    '#default_value' => variable_get('print_mail_link_text', t('Send by email')),
-    '#description' => t('Text used in the link to the send by-email form.'),
-  );
-
-  $form['print_mail_text']['print_mail_text_title'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Form page title'),
-    '#default_value' => variable_get('print_mail_text_title', t('Send page by email')),
-    '#description' => t("Text used as the page title of the mail submission form. Requires a menu rebuild to apply."),
-  );
-  $form['print_mail_text']['print_mail_text_subject'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Message subject'),
-    '#default_value' => variable_get('print_mail_text_subject', t('!user has sent you a message from !site')),
-    '#description' => t("email subject line. The sender's name will appear in place of !user in the subject. The web site name will be inserted in place of !site. The page title replaces !title."),
-  );
-  $form['print_mail_text']['print_mail_text_message'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Message preamble'),
-    '#default_value' => variable_get('print_mail_text_message', t('Message from sender')),
-    '#description' => t('email message preamble. The sender will be able to add their own message after this.'),
+    '#title' => t('Custom link text'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
   );
-  $form['print_mail_text']['print_mail_text_content'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Message content'),
-    '#default_value' => variable_get('print_mail_text_content', ''),
-    '#description' => t('Set the default contents of the message.'),
+  $form['settings']['link_text']['print_mail_link_text_enabled'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable custom link text'),
+    '#default_value' => variable_get('print_mail_link_text_enabled', PRINT_TYPE_LINK_TEXT_ENABLED_DEFAULT),
   );
-  $form['print_mail_text']['print_mail_text_confirmation'] = array(
+  $form['settings']['link_text']['print_mail_link_text'] = array(
     '#type' => 'textfield',
-    '#title' => t('Thank you message'),
-    '#default_value' => variable_get('print_mail_text_confirmation', t('Thank you for spreading the word about !site.')),
-    '#description' => t('This message will be displayed after the user successfully submits the form.'),
-  );
-  $form['print_mail_text']['reset'] = array(
-    '#type' => 'submit',
-    '#value' => t('Reset to defaults'),
-    '#submit' => array('print_mail_strings_settings_delete'),
+    '#default_value' => variable_get('print_mail_link_text', $link['text']),
+    '#description' => t('Text used in the link to the send by email form.'),
   );
 
   return system_settings_form($form);
 }
-
-/**
- * Reset button callback for text strings settings form
- *
- * @ingroup forms
- */
-function print_mail_strings_settings_delete() {
-  variable_del('print_mail_link_text');
-  variable_del('print_mail_text_title');
-  variable_del('print_mail_text_subject');
-  variable_del('print_mail_text_message');
-  variable_del('print_mail_text_content');
-  variable_del('print_mail_text_confirmation');
-}

+ 131 - 44
sites/all/modules/contrib/admin/print/print_mail/print_mail.inc

@@ -10,19 +10,15 @@
  * @ingroup print
  */
 
-require_once(DRUPAL_ROOT . '/' . drupal_get_path('module', 'print') . '/print.pages.inc');
-
 // Include MIME library
 @include_once('Mail/mime.php');
 
 /**
- * Menu callback for the send by email form.
+ * Form constructor for the send by email form.
  *
  * @ingroup forms
  */
 function print_mail_form($form, &$form_state) {
-  global $user;
-
   // Remove the printmail/ prefix
   $path_arr = explode('/', $_GET['q']);
   unset($path_arr[0]);
@@ -30,13 +26,14 @@ function print_mail_form($form, &$form_state) {
   if (empty($path)) {
     // If no path was provided, let's try to generate a page for the referer
     global $base_url;
+    $link = print_mail_print_link();
 
     $ref = $_SERVER['HTTP_REFERER'];
     $path = preg_replace("!^$base_url/!", '', $ref);
     if (($path === $ref) || empty($path)) {
       $path = variable_get('site_frontpage', 'node');
     }
-    drupal_goto(PRINTMAIL_PATH . '/' . $path);
+    drupal_goto($link['path'] . '/' . $path);
   }
   elseif (ctype_digit($path_arr[1])) {
     if (drupal_lookup_path('source', $path)) {
@@ -56,6 +53,19 @@ function print_mail_form($form, &$form_state) {
   $query = $_GET;
   unset($query['q']);
 
+  return print_mail_form_for_path($form, $form_state, $path, $query);
+}
+
+/**
+ * Build email form for the page provided in the path argument.
+ *
+ * @ingroup forms
+ */
+function print_mail_form_for_path($form, &$form_state, $path, $query = NULL, $user = NULL) {
+  if ($user === NULL) {
+    global $user;
+  }
+
   $print_mail_hourly_threshold = variable_get('print_mail_hourly_threshold', PRINT_MAIL_HOURLY_THRESHOLD);
 
   if ((!user_access('send unlimited emails')) && (!flood_is_allowed('print_mail', $print_mail_hourly_threshold))) {
@@ -68,11 +78,26 @@ function print_mail_form($form, &$form_state) {
 
   $print_mail_teaser_default = variable_get('print_mail_teaser_default', PRINT_MAIL_TEASER_DEFAULT_DEFAULT);
   $print_mail_teaser_choice = variable_get('print_mail_teaser_choice', PRINT_MAIL_TEASER_CHOICE_DEFAULT);
+  $print_mail_user_recipients_default = variable_get('print_mail_user_recipients', PRINT_MAIL_USER_RECIPIENTS_DEFAULT);
   $form = array();
 
   $cid = isset($_GET['comment']) ? (int)$_GET['comment'] : NULL;
   $title = _print_get_title($path);
 
+  if ($print_mail_user_recipients_default) {
+    $options = array();
+    if (module_exists('realname')) {
+      $sql = "SELECT u.mail, r.realname AS name from {users} u LEFT JOIN {realname} r ON u.uid = r.uid WHERE u.uid <> :uid ORDER BY name ASC";
+    }
+    else {
+      $sql = "SELECT mail, name from {users} WHERE uid <> :uid ORDER BY name ASC";
+    }
+    $recipients = db_query($sql, array(':uid' => drupal_anonymous_user()->uid));
+    foreach ($recipients as $recipient) {
+      $options[$recipient->mail] = $recipient->name;
+    }
+  }
+
   if (count($form_state['input']) == 0) {
     $nodepath = drupal_get_normal_path($path);
     db_merge('print_mail_page_counter')
@@ -101,14 +126,26 @@ function print_mail_form($form, &$form_state) {
     '#title' => t('Your name'),
     '#size' => 62,
   );
-  $form['txt_to_addrs'] = array(
+  $form['txt_to'] = array(
+    '#tree' => TRUE,
+  );
+  $form['txt_to']['addrs'] = array(
     '#type' => 'textarea',
     '#title' => t('Send to'),
     '#rows' => 3,
     '#resizable' => FALSE,
     '#description' => t('Enter multiple addresses separated by commas and/or different lines.'),
-    '#required' => TRUE,
+    '#required' => !$print_mail_user_recipients_default,
   );
+  if ($print_mail_user_recipients_default) {
+    $form['txt_to']['users'] = array(
+      '#type' => 'select',
+      '#title' => t('Send to users'),
+      '#multiple' => TRUE,
+      '#size' => 10,
+      '#options' => $options,
+    );
+  }
   $form['fld_subject'] = array(
     '#type' => 'textfield',
     '#title' => t('Subject'),
@@ -116,8 +153,8 @@ function print_mail_form($form, &$form_state) {
     '#required' => TRUE,
   );
   if (!empty($title)) {
-    // To prevent useless translation strings, try to translate only node titles
-    if (drupal_substr($path, 0, 5) == 'node/') {
+    // To prevent useless translation strings, try to translate only non-node titles
+    if (drupal_substr($path, 0, 5) != 'node/') {
       $title = t($title);
     }
 
@@ -150,10 +187,6 @@ function print_mail_form($form, &$form_state) {
     '#type' => 'submit',
     '#value' => t('Send email'),
   );
-  $form['btn_clear'] = array(
-    '#type' => 'markup',
-    '#markup' => '<input type="reset" name="clear" id="edit-btn-clear" value="' . t('Clear form') . '" class="form-submit" />',
-  );
   $form['btn_cancel'] = array(
     '#name' => 'cancel',
     '#type' => 'submit',
@@ -171,33 +204,37 @@ function print_mail_form($form, &$form_state) {
     $user_name = t('Someone');
   }
   $site_name = variable_get('site_name', t('an interesting site'));
-  $print_mail_text_subject = filter_xss(variable_get('print_mail_text_subject', t('!user has sent you a message from !site')));
-  $form['fld_subject']['#default_value'] = t($print_mail_text_subject, array('!user' => $user_name, '!site' => $site_name, '!title' => $title));
-  $print_mail_text_content = filter_xss(variable_get('print_mail_text_content', ''));
-  $form['txt_message']['#default_value'] = t($print_mail_text_content);
+  $form['fld_subject']['#default_value'] = t('!user has sent you a message from !site', array('!user' => $user_name, '!site' => $site_name, '!title' => $title));
+  $form['txt_message']['#default_value'] = t('');
 
   return $form;
 }
 
 /**
- * Theme function for the send by-email form submission.
+ * Returns HTML for the send by-email form.
  *
  * Adds a class to the form labels. This class is used to place the label on
  * the left of the input fields.
  *
+ * @param array $form
+ *   Form array
+ *
+ * @see print_mail_form()
  * @ingroup forms
+ * @ingroup themeable
+ * @ingroup print_themeable
  */
 function theme_print_mail_form($variables) {
   $form = $variables['form'];
 
-  drupal_add_css(drupal_get_path('module', 'print') . '/css/printlinks.css');
+  drupal_add_css(drupal_get_path('module', 'print_mail') . '/css/print_mail.theme.css');
   $content = '';
   foreach (element_children($form) as $key) {
     $tmp = drupal_render($form[$key]);
     switch ($key) {
       case 'fld_from_addr':
       case 'fld_from_name':
-      case 'txt_to_addrs':
+      case 'txt_to':
       case 'fld_subject':
       case 'fld_title':
         $tmp = str_replace('<label', '<label class ="printmail-label"', $tmp);
@@ -209,11 +246,44 @@ function theme_print_mail_form($variables) {
 }
 
 /**
- * Validate the send by-email form submission.
+ * Theme function for the email sending just the link.
+ *
+ * Allows themes and modules to override the default sendlink plain text format.
+ *
+ * @param $params
+ *   $params as passed to print_mail_mail().
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_mail_sendlink_plain($params) {
+  return $params['message'] . '\n\n' . $params['link'];
+}
+
+/**
+ * Theme function for the email sending just the link.
  *
+ * Allows themes and modules to override the default sendlink HTML format.
+ *
+ * @param $params
+ *   $params as passed to print_mail_mail().
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_mail_sendlink_html($params) {
+  return $params['message'] . '<br/><br/>' . l($params['title'], $params['link']);
+}
+
+/**
+ * Form validation handler for print_mail_form().
+ *
+ * @see print_mail_form()
  * @ingroup forms
  */
 function print_mail_form_validate($form, &$form_state) {
+  $print_mail_user_recipients_default = variable_get('print_mail_user_recipients', PRINT_MAIL_USER_RECIPIENTS_DEFAULT);
+
   if (array_key_exists('cancel', $form_state['input'])) {
     form_set_error(NULL, '', TRUE);
     drupal_get_messages('error');
@@ -227,10 +297,22 @@ function print_mail_form_validate($form, &$form_state) {
     form_set_error('fld_from_addr', $test);
   }
 
-  // All new-lines are replaced by commas
-  $to_addrs = preg_replace('![\r|\n|,]+!', ',', trim($form_state['values']['txt_to_addrs']));
-  // Create an array from the string
-  $to_array = explode(',', $to_addrs);
+  $to_array = array();
+  if (!empty($form_state['values']['txt_to']['users'])) {
+    $to_array = array_values($form_state['values']['txt_to']['users']);
+  }
+
+  if (!empty($form_state['values']['txt_to']['addrs'])) {
+    // All new-lines are replaced by commas
+    $to_addrs = preg_replace('![\r|\n|,]+!', ',', trim($form_state['values']['txt_to']['addrs']));
+    // Create an array from the string
+    $to_array = array_merge($to_array, explode(',', $to_addrs));
+  }
+
+  if (empty($to_array) && $print_mail_user_recipients_default) {
+    form_set_error('txt_to', t('You must specify at least one email address or user as a recipient.'));
+  }
+
   // Verify each element of the array
   foreach ($to_array as $key => $address) {
     $address = trim($address);
@@ -244,14 +326,14 @@ function print_mail_form_validate($form, &$form_state) {
       $test = user_validate_mail($address);
     }
     if ($test) {
-      form_set_error('txt_to_addrs', $test);
+      form_set_error('txt_to', $test);
     }
   }
 
   $print_mail_hourly_threshold = variable_get('print_mail_hourly_threshold', PRINT_MAIL_HOURLY_THRESHOLD);
 
   if ((!user_access('send unlimited emails')) && (!flood_is_allowed('print_mail', $print_mail_hourly_threshold - count($to_array) + 1))) {
-    form_set_error('txt_to_addrs',  t('You cannot send more than %number messages per hour. Please reduce the number of recipients.', array('%number' => $print_mail_hourly_threshold)));
+    form_set_error('txt_to',  t('You cannot send more than %number messages per hour. Please reduce the number of recipients.', array('%number' => $print_mail_hourly_threshold)));
   }
 
   // In all fields, prevent insertion of custom headers
@@ -264,29 +346,33 @@ function print_mail_form_validate($form, &$form_state) {
   $form_state['values']['fld_from_addr'] = $from_addr;
   $form_state['values']['fld_from_name'] = trim($form_state['values']['fld_from_name']);
   // Re-create the string from the re-organized array
-  $form_state['values']['txt_to_addrs'] = implode(', ', $to_array);
+  $form_state['values']['txt_to']['addrs'] = implode(', ', $to_array);
 }
 
 /**
- * Process the send by-email form submission.
+ * Form submission handler for print_mail_form().
  *
+ * @see print_mail_form()
+ * @see print_controller()
  * @ingroup forms
  */
 function print_mail_form_submit($form, &$form_state) {
   if (!array_key_exists('cancel', $form_state['values'])) {
-    $cid = isset($form_state['values']['cid']) ? $form_state['values']['cid'] : NULL;
-    $print_mail_text_message = filter_xss_admin(variable_get('print_mail_text_message', t('Message from sender')));
-    $sender_message = $print_mail_text_message . ':<br /><br /><em>' . nl2br(check_plain($form_state['values']['txt_message'])) . '</em>';
+    module_load_include('inc', 'print', 'print.pages');
+    module_load_include('inc', 'print', 'includes/print');
 
-    $print = print_controller($form_state['values']['path'], $form_state['values']['query'], $cid, PRINT_MAIL_FORMAT, $form_state['values']['chk_teaser'], $sender_message);
+    $link = print_mail_print_link();
+    $cid = isset($form_state['values']['cid']) ? $form_state['values']['cid'] : NULL;
+    $view_mode = $form_state['values']['chk_teaser'] ? 'teaser' : PRINT_VIEW_MODE;
+    $node = print_controller($form_state['values']['path'], $link['format'], $cid, $view_mode);
 
-    if ($print !== FALSE) {
+    if ($node) {
       $print_mail_send_option_default = variable_get('print_mail_send_option_default', PRINT_MAIL_SEND_OPTION_DEFAULT);
 
       $params = array();
       $params['subject'] = $form_state['values']['fld_subject'];
-      $params['message'] = $sender_message;
-      $params['link'] = $print['url'];
+      $params['message'] = t('Message from sender') . ':<br /><br /><em>' . nl2br(check_plain($form_state['values']['txt_message'])) . '</em>';
+      $params['link'] = url($form_state['values']['path'], array('absolute' => TRUE, 'query' => $form_state['values']['query']));
       $params['title'] = $form_state['values']['title'];
 
       // If a name is provided, make From: in the format Common Name <address>
@@ -305,10 +391,9 @@ function print_mail_form_submit($form, &$form_state) {
 
       // Spaces in img URLs must be replaced with %20
       $pattern = '!<(img\s[^>]*?)>!is';
-      $print['content'] = preg_replace_callback($pattern, '_print_replace_spaces', $print['content']);
+      $node->content = preg_replace_callback($pattern, '_print_replace_spaces', $node->content);
 
-      $node = $print['node'];
-      $params['body'] = theme('print', array('print' => $print, 'type' => PRINT_MAIL_FORMAT, 'node' => $node));
+      $params['body'] = theme('print', array('node' => $node, 'query' => $form_state['values']['query'], 'format' => $link['format'], 'expand_css' => TRUE, 'message' => $params['message']));
 
       // Img elements must be set to absolute
       $pattern = '!<(img\s[^>]*?)>!is';
@@ -318,13 +403,16 @@ function print_mail_form_submit($form, &$form_state) {
       $pattern = '!<(a\s[^>]*?)>!is';
       $params['body'] = preg_replace_callback($pattern, '_print_rewrite_urls', $params['body']);
 
+      // Enable support for third-party modules to alter the e-mail before it's sent
+      drupal_alter('print_mail', $params, $to);
+
       $ok = FALSE;
       $use_job_queue = variable_get('print_mail_job_queue', PRINT_MAIL_JOB_QUEUE_DEFAULT);
       if ($use_job_queue) {
         $queue = DrupalQueue::get('print_mail_send');
       }
 
-      $addresses = explode(', ', $form_state['values']['txt_to_addrs']);
+      $addresses = explode(', ', $form_state['values']['txt_to']['addrs']);
       foreach ($addresses as $to) {
         if ($use_job_queue) {
           // Use job queue to send mails during cron runs
@@ -341,10 +429,9 @@ function print_mail_form_submit($form, &$form_state) {
       }
       if ($ok) {
         $query = empty($form_state['values']['query']) ? '' : '?' . rawurldecode(drupal_http_build_query($form_state['values']['query']));
-        watchdog('print_mail', '%name [%from] sent %page to [%to]', array('%name' => $form_state['values']['fld_from_name'], '%from' => $form_state['values']['fld_from_addr'], '%page' => $form_state['values']['path'] . $query, '%to' => $form_state['values']['txt_to_addrs']));
+        watchdog('print_mail', '%name [%from] sent %page to [%to]', array('%name' => $form_state['values']['fld_from_name'], '%from' => $form_state['values']['fld_from_addr'], '%page' => $form_state['values']['path'] . $query, '%to' => $form_state['values']['txt_to']['addrs']));
         $site_name = variable_get('site_name', t('us'));
-        $print_mail_text_confirmation = variable_get('print_mail_text_confirmation', t('Thank you for spreading the word about !site.'));
-        drupal_set_message(check_plain(t($print_mail_text_confirmation, array('!site' => $site_name))));
+        drupal_set_message(check_plain(t('Thank you for spreading the word about !site.', array('!site' => $site_name))));
 
         $nodepath = drupal_get_normal_path($form_state['values']['path']);
         db_update('print_mail_page_counter')

+ 4 - 9
sites/all/modules/contrib/admin/print/print_mail/print_mail.info

@@ -1,18 +1,13 @@
 name = "Send by email"
 description = "Provides the capability to send the web page by email"
-core=7.x
+core = 7.x
 package = "Printer, email and PDF versions"
 dependencies[] = print
-files[] = print_mail.module
-files[] = print_mail.inc
-files[] = print_mail.admin.inc
-files[] = print_mail.install
-files[] = print_mail.views.inc
 configure = admin/config/user-interface/print/email
 
-; Information added by drupal.org packaging script on 2012-09-04
-version = "7.x-1.2"
+; Information added by Drupal.org packaging script on 2014-04-02
+version = "7.x-2.0"
 core = "7.x"
 project = "print"
-datestamp = "1346768900"
+datestamp = "1396426766"
 

+ 45 - 22
sites/all/modules/contrib/admin/print/print_mail/print_mail.install

@@ -40,29 +40,26 @@ function print_mail_disable() {
  * Implements hook_uninstall().
  */
 function print_mail_uninstall() {
-  variable_del('print_mail_settings');
-  variable_del('print_mail_show_link');
-  variable_del('print_mail_link_pos');
-  variable_del('print_mail_link_teaser');
-  variable_del('print_mail_node_link_visibility');
-  variable_del('print_mail_node_link_pages');
-  variable_del('print_mail_link_class');
-  variable_del('print_mail_sys_link_visibility');
-  variable_del('print_mail_sys_link_pages');
-  variable_del('print_mail_book_link');
+  variable_del('print_mail_display_sys_urllist');
   variable_del('print_mail_hourly_threshold');
-  variable_del('print_mail_use_reply_to');
-  variable_del('print_mail_teaser_default');
-  variable_del('print_mail_teaser_choice');
+  variable_del('print_mail_job_queue');
   variable_del('print_mail_link_text');
+  variable_del('print_mail_link_text_enabled');
+  variable_del('print_mail_send_option_default');
+  variable_del('print_mail_teaser_choice');
+  variable_del('print_mail_teaser_default');
+  variable_del('print_mail_use_reply_to');
+  variable_del('print_mail_user_recipients');
+
+  variable_del('print_mail_book_link');
+  variable_del('print_mail_link_class');
+  variable_del('print_mail_link_pos');
+  variable_del('print_mail_link_teaser');
   variable_del('print_mail_link_use_alias');
-  variable_del('print_mail_text_title');
-  variable_del('print_mail_text_confirmation');
-  variable_del('print_mail_text_message');
-  variable_del('print_mail_text_subject');
-  variable_del('print_mail_text_content');
-  variable_del('print_mail_job_queue');
-  variable_del('print_mail_display_sys_urllist');
+  variable_del('print_mail_show_link');
+  variable_del('print_mail_sys_link_pages');
+  variable_del('print_mail_sys_link_visibility');
+
   $settings = db_query("SELECT name FROM {variable} WHERE name LIKE 'print\_mail\_display\_%'");
   foreach ($settings as $variable) {
     variable_del($variable->name);
@@ -115,7 +112,7 @@ function print_mail_schema() {
     'fields' => array(
       'path' => array(
         'type' => 'varchar',
-        'length' => 128,
+        'length' => 255,
         'not null' => TRUE,
         'description' => 'Page path',
       ),
@@ -192,12 +189,38 @@ function print_mail_update_7101(&$sandbox) {
     ->execute();
 }
 
+/**
+ * Delete old variables
+ */
+function print_mail_update_7200(&$sandbox) {
+  variable_del('print_mail_settings');
+
+  variable_del('print_mail_node_link_pages');
+  variable_del('print_mail_node_link_visibility');
+
+  variable_del('print_mail_text_title');
+  variable_del('print_mail_text_confirmation');
+  variable_del('print_mail_text_message');
+  variable_del('print_mail_text_subject');
+  variable_del('print_mail_text_content');
+}
+
 /**
  * Enable block and help area links
  */
-function print_mail_update_7102(&$sandbox) {
+function print_mail_update_7202(&$sandbox) {
   $link_pos = variable_get('print_mail_link_pos', drupal_json_decode('{ "link": "link", "block": "block", "help": "help" }'));
   $link_pos['block'] = 'block';
   $link_pos['help'] = 'help';
   variable_set('print_mail_link_pos', $link_pos);
 }
+
+/**
+ * Increase size of the path field in the print_mail_page_counter table
+ */
+function print_mail_update_7203(&$sandbox) {
+  db_drop_primary_key('print_mail_page_counter');
+  db_change_field('print_mail_page_counter', 'path', 'path',
+    array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'description' => 'Page path'),
+    array('primary key' => array('path')));
+}

+ 104 - 398
sites/all/modules/contrib/admin/print/print_mail/print_mail.module

@@ -7,27 +7,28 @@
  * @ingroup print
  */
 
-define('PRINTMAIL_PATH', 'printmail');
-
-// Defined in print.module
-// define('PRINT_MAIL_FORMAT', 'mail');
-
-define('PRINT_MAIL_LINK_POS_DEFAULT', '{ "link": "link", "block": "block", "help": "help" }');
-define('PRINT_MAIL_LINK_TEASER_DEFAULT', 0);
-define('PRINT_MAIL_SHOW_LINK_DEFAULT', 1);
-define('PRINT_MAIL_NODE_LINK_VISIBILITY_DEFAULT', 0);
-define('PRINT_MAIL_NODE_LINK_PAGES_DEFAULT', '');
-define('PRINT_MAIL_LINK_CLASS_DEFAULT', 'print-mail');
-define('PRINT_MAIL_SYS_LINK_VISIBILITY_DEFAULT', 1);
-define('PRINT_MAIL_SYS_LINK_PAGES_DEFAULT', '');
-define('PRINT_MAIL_LINK_USE_ALIAS_DEFAULT', 0);
-define('PRINT_MAIL_BOOK_LINK_DEFAULT', 1);
 define('PRINT_MAIL_HOURLY_THRESHOLD', 3);
 define('PRINT_MAIL_USE_REPLY_TO', TRUE);
 define('PRINT_MAIL_TEASER_DEFAULT_DEFAULT', 1);
 define('PRINT_MAIL_TEASER_CHOICE_DEFAULT', 0);
 define('PRINT_MAIL_SEND_OPTION_DEFAULT', 'sendpage');
 define('PRINT_MAIL_JOB_QUEUE_DEFAULT', 0);
+define('PRINT_MAIL_USER_RECIPIENTS_DEFAULT', 0);
+
+/**
+ * Implements hook_print_link().
+ */
+function print_mail_print_link() {
+  return array(
+    'format' => 'mail',
+    'text' => t('Send by email'),
+    'description' => t('Send this page by email.'),
+    'path' => 'printmail',
+    'class' => 'print-mail',
+    'icon' => 'mail_icon.png',
+    'module' => 'print_mail',
+  );
+}
 
 /**
  * Implements hook_permission().
@@ -50,13 +51,18 @@ function print_mail_permission() {
  */
 function print_mail_theme() {
   return array(
-    'print_mail_format_link' => array(
-      'variables' => array(),
-    ),
     'print_mail_form' => array(
       'render element' => 'form',
       'file' => 'print_mail.inc',
     ),
+    'print_mail_sendlink_html' => array(
+      'variables' => array('params' => NULL),
+      'file' => 'print_mail.inc',
+    ),
+    'print_mail_sendlink_plain' => array(
+      'variables' => array('params' => NULL),
+      'file' => 'print_mail.inc',
+    ),
   );
 }
 
@@ -64,10 +70,11 @@ function print_mail_theme() {
  * Implements hook_menu().
  */
 function print_mail_menu() {
+  $link = print_mail_print_link();
   $items = array();
 
-  $items[PRINTMAIL_PATH] = array(
-    'title' => variable_get('print_mail_text_title', 'Send page by email'),
+  $items[$link['path']] = array(
+    'title' => 'Send by email',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('print_mail_form'),
     'access callback' => '_print_mail_access',
@@ -75,7 +82,7 @@ function print_mail_menu() {
     'type' => MENU_CALLBACK,
     'file' => 'print_mail.inc',
   );
-  $items[PRINTMAIL_PATH . '/' . PRINTMAIL_PATH] = array(
+  $items[$link['path'] . '/' . $link['path']] = array(
     'access callback' => FALSE,
   );
   $items['admin/config/user-interface/print/email'] = array(
@@ -88,25 +95,26 @@ function print_mail_menu() {
     'type' => MENU_LOCAL_TASK,
     'file' => 'print_mail.admin.inc',
   );
-  $items['admin/config/user-interface/print/email/options'] = array(
-    'title' => 'Options',
-    'weight' => 1,
-    'type' => MENU_DEFAULT_LOCAL_TASK,
-  );
-  $items['admin/config/user-interface/print/email/strings'] = array(
-    'title' => 'Text strings',
-    'description' => 'Override the user-facing strings used in the send by email version.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('print_mail_strings_settings'),
-    'access arguments'  => array('administer print'),
-    'weight' => 2,
-    'type' => MENU_LOCAL_TASK,
-    'file' => 'print_mail.admin.inc',
-  );
 
   return $items;
 }
 
+/**
+ * Implements hook_variable_info().
+ */
+function print_mail_variable_info($options) {
+  $link = print_mail_print_link();
+
+  $variable['print_mail_link_text'] = array(
+    'title' => t('Send by email'),
+    'description' => t('Text used in the link to the send by email form.'),
+    'type' => 'string',
+    'default' => t($link['text']),
+  );
+
+  return $variable;
+}
+
 /**
  * Implements hook_requirements().
  */
@@ -136,207 +144,41 @@ function print_mail_requirements($phase) {
  * Implements hook_block_info().
  */
 function print_mail_block_info() {
-      $block['print_mail-top']['info'] = t('Most emailed');
-      $block['print_mail-top']['cache'] = DRUPAL_CACHE_GLOBAL;
-      return $block;
+  $block['print_mail-top']['info'] = t('Most emailed');
+  $block['print_mail-top']['cache'] = DRUPAL_CACHE_GLOBAL;
+  return $block;
 }
 
 /**
  * Implements hook_block_view().
  */
 function print_mail_block_view($delta = 0) {
-      switch ($delta) {
-      case 'print_mail-top':
-        $block['subject'] = t('Most emailed');
-        $result = db_query_range("SELECT path FROM {print_mail_page_counter} LEFT JOIN {node} n ON path = CONCAT('node/', n.nid) WHERE status <> 0 OR status IS NULL ORDER BY sentcount DESC", 0, 3)
-                    ->fetchAll();
-        if (count($result)) {
-          $block['content'] = '<div class="item-list"><ul>';
-          foreach ($result as $obj) {
-            $block['content'] .= '<li>' . l(_print_get_title($obj->path), $obj->path) . '</li>';
-          }
-          $block['content'] .= '</ul></div>';
+  switch ($delta) {
+    case 'print_mail-top':
+      $block['subject'] = t('Most emailed');
+      $result = db_query_range("SELECT path FROM {print_mail_page_counter} LEFT JOIN {node} n ON path = CONCAT('node/', n.nid) WHERE status <> 0 OR status IS NULL ORDER BY sentcount DESC", 0, 3)
+                  ->fetchAll();
+      if (count($result)) {
+        $items = array();
+        foreach ($result as $obj) {
+          $items[] = l(_print_get_title($obj->path), $obj->path);
         }
-        break;
+        $block['content'] = theme('item_list', array('items' => $items, 'type' => 'ul'));
       }
-      return $block;
-}
-
-/**
- * Implements hook_node_view().
- */
-function print_mail_node_view($node, $view_mode) {
-  $print_mail_link_pos = variable_get('print_mail_link_pos', drupal_json_decode(PRINT_MAIL_LINK_POS_DEFAULT));
-  $print_mail_link_use_alias = variable_get('print_mail_link_use_alias', PRINT_MAIL_LINK_USE_ALIAS_DEFAULT);
-
-  foreach (array('node', 'comment') as $type) {
-    $allowed_type = print_mail_link_allowed(array('type' => $type, 'node' => $node, 'view_mode' => $view_mode));
-    if (($allowed_type) && !empty($print_mail_link_pos['link'])) {
-      drupal_add_css(drupal_get_path('module', 'print') . '/css/printlinks.css');
-      $links = array();
-      $format = theme('print_mail_format_link');
-
-      // Show book link
-      if ($allowed_type === PRINT_ALLOW_BOOK_LINK) {
-        $links['book_mail'] = array(
-          'href' => PRINTMAIL_PATH . '/book/export/html/' . $node->nid,
-          'title' => $format['text'],
-          'attributes' => $format['attributes'],
-          'html' => $format['html'],
-        );
-      }
-      elseif ($allowed_type === PRINT_ALLOW_NORMAL_LINK) {
-        $path = (($print_mail_link_use_alias) && ($alias = drupal_lookup_path('alias', 'node/' . $node->nid))) ? $alias : $node->nid;
-
-        $links['print_mail'] = array(
-          'href' => PRINTMAIL_PATH . '/' . $path,
-          'title' => $format['text'],
-          'attributes' => $format['attributes'],
-          'html' => $format['html'],
-          'query' => print_query_string_encode($_GET, array('q')),
-        );
-      }
-
-      $link_content = array(
-        '#theme' => 'links',
-        '#links' => $links,
-        '#attributes' => array('class' => array('links', 'inline')),
-      );
-
-      if ($type == 'node') {
-        $node->content['links']['print_mail'] = $link_content;
-      }
-      elseif (($type == 'comment') && isset($node->content['comments']['comments'])) {
-        foreach ($node->content['comments']['comments'] as $cid => $comment) {
-          if (is_numeric($cid)) {
-            $link_content['#links']['print_mail']['query']['comment'] = $cid;
-            $node->content['comments']['comments'][$cid]['links']['print_mail'] = $link_content;
-          }
-        }
-      }
-    }
-  }
-
-  // Insert content corner links
-  if (!empty($print_mail_link_pos['corner']) && ($view_mode == 'full')) {
-    $node->content['print_links']['#markup'] .= print_mail_insert_link(NULL, $node);
-  }
-}
-
-/**
- * Implements hook_help().
- */
-function print_mail_help($path, $arg) {
-  $print_mail_link_pos = variable_get('print_mail_link_pos', drupal_json_decode(PRINT_MAIL_LINK_POS_DEFAULT));
-  if (($path !== 'node/%') && !(empty($print_mail_link_pos['help']))) {
-    static $output = FALSE;
-
-    if ($output === FALSE) {
-      $output = TRUE;
-
-      $link = print_mail_insert_link();
-      if ($link) {
-        return "<span class='print-syslink'>$link</span>";
-      }
-    }
-  }
-}
-
-/**
- * Implements hook_node_load().
- */
-function print_mail_node_load($nodes, $types) {
-  $ids = array();
-  foreach ($nodes as $node) {
-    $ids[] = $node->nid;
-  }
-
-  $result = db_query('SELECT nid, link, comments, url_list FROM {print_mail_node_conf} WHERE nid IN (:nids)', array(':nids' => $ids))->fetchAllAssoc('nid');
-
-  foreach ($nodes as $node) {
-    $node->print_mail_display = isset($result[$node->nid]) ? intval($result[$node->nid]->link) : variable_get('print_mail_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-    $node->print_mail_display_comment = isset($result[$node->nid]) ? intval($result[$node->nid]->comments) : variable_get('print_mail_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-    $node->print_mail_display_urllist = isset($result[$node->nid]) ? intval($result[$node->nid]->url_list) : variable_get('print_mail_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-  }
-}
-
-/**
- * Implements hook_node_insert().
- */
-function print_mail_node_insert($node) {
-  if (user_access('administer print') || user_access('node-specific print configuration')) {
-    if (!isset($node->print_mail_display)) $node->print_mail_display = variable_get('print_mail_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-    if (!isset($node->print_mail_display_comment)) $node->print_mail_display_comment = variable_get('print_mail_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-    if (!isset($node->print_mail_display_urllist)) $node->print_mail_display_urllist = variable_get('print_mail_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-
-    _print_mail_node_conf_modify($node->nid, $node->print_mail_display, $node->print_mail_display_comment, $node->print_mail_display_urllist);
-  }
-}
-
-/**
- * Implements hook_node_update().
- */
-function print_mail_node_update($node) {
-  if (user_access('administer print') || user_access('node-specific print configuration')) {
-    if (!isset($node->print_mail_display)) $node->print_mail_display = variable_get('print_mail_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-    if (!isset($node->print_mail_display_comment)) $node->print_mail_display_comment = variable_get('print_mail_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-    if (!isset($node->print_mail_display_urllist)) $node->print_mail_display_urllist = variable_get('print_mail_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-
-    _print_mail_node_conf_modify($node->nid, $node->print_mail_display, $node->print_mail_display_comment, $node->print_mail_display_urllist);
+      break;
   }
+  return $block;
 }
 
 /**
  * Implements hook_node_delete().
  */
 function print_mail_node_delete($node) {
-  db_delete('print_mail_node_conf')
-    ->condition('nid', $node->nid)
-    ->execute();
   db_delete('print_mail_page_counter')
     ->condition('path', 'node/' . $node->nid)
     ->execute();
 }
 
-/**
- * Implements hook_form_alter().
- */
-function print_mail_form_alter(&$form, &$form_state, $form_id) {
-  // Add the node-type settings option to activate the mail version link
-  if ((user_access('administer print') || user_access('node-specific print configuration')) &&
-      (($form_id == 'node_type_form') || !empty($form['#node_edit_form']))) {
-    $form['print']['mail_label'] = array(
-      '#type' => 'markup',
-      '#markup' => '<p><strong>' . t('Send by email') . '</strong></p>',
-    );
-
-    $form['print']['print_mail_display'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show link'),
-    );
-    $form['print']['print_mail_display_comment'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show link in individual comments'),
-    );
-    $form['print']['print_mail_display_urllist'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show Printer-friendly URLs list'),
-    );
-
-    if ($form_id == 'node_type_form') {
-      $form['print']['print_mail_display']['#default_value'] = variable_get('print_mail_display_' . $form['#node_type']->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-      $form['print']['print_mail_display_comment']['#default_value'] = variable_get('print_mail_display_comment_' . $form['#node_type']->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-      $form['print']['print_mail_display_urllist']['#default_value'] = variable_get('print_mail_display_urllist_' . $form['#node_type']->type, PRINT_TYPE_URLLIST_DEFAULT);
-    }
-    else {
-      $node = $form['#node'];
-      $form['print']['print_mail_display']['#default_value'] = isset($node->print_mail_display) ? $node->print_mail_display : variable_get('print_mail_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-      $form['print']['print_mail_display_comment']['#default_value'] = isset($node->print_mail_display_comment) ? $node->print_mail_display_comment : variable_get('print_mail_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-      $form['print']['print_mail_display_urllist']['#default_value'] = isset($node->print_mail_display_urllist) ? $node->print_mail_display_urllist : variable_get('print_mail_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-    }
-  }
-}
-
 /**
  * Implements hook_cron_queue_info().
  */
@@ -348,6 +190,19 @@ function print_mail_cron_queue_info() {
   return $queues;
 }
 
+/**
+ * Worker callback for print_mail_cron_queue_info()
+ *
+ * @param array $data
+ *   An associative array containing:
+ *   - module: A module name to invoke hook_mail() on.
+ *   - key: A key to identify the e-mail sent.
+ *   - to: The e-mail address or addresses where the message will be sent to.
+ *   - language: Language object to use to compose the e-mail.
+ *   - params: Optional parameters to build the e-mail.
+ *   - from: Sets From to this value, if given.
+ *   These are the input arguments of the drupal_mail() function.
+ */
 function print_mail_send($data) {
   drupal_mail($data['module'], $data['key'], $data['to'], $data['language'], $data['params'], $data['from']);
 }
@@ -369,8 +224,8 @@ function print_mail_mail($key, &$message, $params) {
       break;
     case 'sendlink':
       // Generate plain-text and html versions of message with link
-      $sendlink_plain = $params['message'] . '\n\n' . $params['link'];
-      $sendlink_html = $params['message'] . '<br/><br/>' . l($params['title'], $params['link']);
+      $sendlink_plain = theme('print_mail_sendlink_plain', $params);
+      $sendlink_html = theme('print_mail_sendlink_html', $params);
 
       // Send HTML-only version if MIME library not present
       if (!class_exists('Mail_mime')) {
@@ -416,15 +271,17 @@ function print_mail_mail($key, &$message, $params) {
 /**
  * Access callback to check a combination of user_acess() and page access
  *
- * @param $permission
+ * @param string $permission
  *   permission required to view the page
- * @return
+ *
+ * @return bool
  *   TRUE if the user has permission to view the page, FALSE otherwise
  */
 function _print_mail_access($permission) {
+  $link = print_mail_print_link();
   $page_access = TRUE;
   $parts = explode('/', $_GET['q']);
-  if ($parts[0] == PRINTMAIL_PATH) {
+  if ($parts[0] == $link['path']) {
     if (count($parts) > 1) {
       unset($parts[0]);
       $path = implode('/', $parts);
@@ -451,109 +308,29 @@ function _print_mail_access($permission) {
   return (user_access($permission) && $page_access);
 }
 
-/**
- * Update the print_mail_node_conf table to reflect the given attributes
- *
- * If updating to the default values, delete the record.
- *
- * @param $nid
- *   value of the nid field (primary key)
- * @param $link
- *   value of the link field (0 or 1)
- * @param $comments
- *   value of the comments field (0 or 1)
- * @param $url_list
- *   value of the url_list field (0 or 1)
- */
-function _print_mail_node_conf_modify($nid, $link, $comments, $url_list) {
-    db_merge('print_mail_node_conf')
-      ->key(array('nid' => $nid))
-      ->fields(array(
-        'link' => $link,
-        'comments' => $comments,
-        'url_list' => $url_list,
-      ))
-      ->execute();
-}
-
-/**
- * Format the send by email link
- *
- * @return
- *   array of formatted attributes
- * @ingroup themeable
- */
-function theme_print_mail_format_link() {
-  $print_mail_link_class  = variable_get('print_mail_link_class', PRINT_MAIL_LINK_CLASS_DEFAULT);
-  $print_mail_show_link = variable_get('print_mail_show_link', PRINT_MAIL_SHOW_LINK_DEFAULT);
-  $print_mail_link_text = filter_xss(variable_get('print_mail_link_text', t('Send by email')));
-
-  $img = drupal_get_path('module', 'print') . '/icons/mail_icon.gif';
-  $title = t('Send this page by email.');
-  $class = strip_tags($print_mail_link_class);
-  $new_window = FALSE;
-  $format = _print_format_link_aux($print_mail_show_link, $print_mail_link_text, $img);
-
-  return array('text' => $format['text'],
-               'html' => $format['html'],
-               'attributes' => print_fill_attributes($title, $class, $new_window),
-              );
-}
-
 /**
  * Auxiliary function to display a formatted send by email link
  *
  * Function made available so that developers may call this function from
  * their defined pages/blocks.
  *
- * @param $path
- *   path of the original page (optional). If not specified, the current URL
- *   is used
- * @param $node
- *   an optional node object, to be used in defining the path, if used, the
- *   path argument is irrelevant
- * @return
+ * @param string $path
+ *   path to be used in the link. If not specified, the current URL is used.
+ * @param object $node
+ *   node object, to be used in checking node access. If the path argument is
+ *   not provided, the path used will be node/nid.
+ * @param string $location
+ *   where in the page where the link is being inserted ('link', 'corner',
+ *   'block', 'help').
+ *
+ * @return string
  *   string with the HTML link to the printer-friendly page
+ *
+ * @ingroup print_api
  */
-function print_mail_insert_link($path = NULL, $node = NULL) {
-  if ($node !== NULL) {
-    $nid = $node->nid;
-    $path = 'node/' . $nid;
-    $allowed_type = print_mail_link_allowed(array('node' => $node));
-  }
-  else {
-    if ($path === NULL) {
-      $nid = preg_replace('!^node/([\d]+)!', '$1', $_GET['q']);
-      $path = $_GET['q'];
-    }
-    else {
-      $nid = NULL;
-    }
-    $allowed_type = print_mail_link_allowed(array('path' => $path));
-  }
-
-  if ($allowed_type) {
-    if ($nid !== NULL) {
-      if ($allowed_type === PRINT_ALLOW_BOOK_LINK) {
-        $path = 'book/export/html/' . $nid;
-      }
-      else {
-        if (variable_get('print_mail_link_use_alias', PRINT_MAIL_LINK_USE_ALIAS_DEFAULT) && ($alias = drupal_lookup_path('alias', $path))) {
-          $path = $alias;
-        }
-        else {
-          $path = $nid;
-        }
-      }
-      $path = PRINTMAIL_PATH . '/' . $path;
-      $query = print_query_string_encode($_GET, array('q'));
-    }
-    else {
-      $query = NULL;
-    }
-    drupal_add_css(drupal_get_path('module', 'print') . '/css/printlinks.css');
-    $format = theme('print_mail_format_link');
-    return '<span class="print_mail">' . l($format['text'], $path, array('attributes' => $format['attributes'], 'query' => $query, 'absolute' => TRUE, 'html' => $format['html'])) . '</span>';
+function print_mail_insert_link($path = NULL, $node = NULL, $location = '') {
+  if (function_exists('print_ui_insert_link')) {
+    return print_ui_insert_link(print_mail_print_link(), array('path' => $path, 'node' => $node, 'location' => $location));
   }
   else {
     return FALSE;
@@ -563,86 +340,15 @@ function print_mail_insert_link($path = NULL, $node = NULL) {
 /**
  * Check if the link to send by email is allowed depending on the settings
  *
- * @param $args
+ * @param array $args
  *   array containing the possible parameters:
- *    teaser, node, type, path
- * @return
- *   FALSE if not allowed
- *   PRINT_ALLOW_NORMAL_LINK if a normal link is allowed
- *   PRINT_ALLOW_BOOK_LINK if a link is allowed in a book node
+ *    view_mode, node, type, path
+ *
+ * @return bool
+ *   FALSE if not allowed, TRUE otherwise
  */
 function print_mail_link_allowed($args) {
-  $view_mode = isset($args['view_mode']) ? $args['view_mode'] : '';
-  if ((($view_mode == 'teaser') && !variable_get('print_mail_link_teaser', PRINT_MAIL_LINK_TEASER_DEFAULT))
-      || !in_array($view_mode, array('full', 'teaser', '')) || !user_access('access send by email')) {
-    // If the teaser link is disabled or the user is not allowed
-    return FALSE;
-  }
-  if (!empty($args['path'])) {
-    $nid = preg_replace('!^node/!', '', drupal_get_normal_path($args['path']));
-    if (ctype_digit($nid)) {
-      $args['node'] = node_load($nid);
-    }
-  }
-  if (!empty($args['node'])) {
-    static $node_type = FALSE;
-
-    $node = $args['node'];
-    if (isset($node->type)) {
-      $node_type = $node->type;
-    }
-    // Node
-    $print_mail_node_link_visibility = variable_get('print_mail_node_link_visibility', PRINT_MAIL_NODE_LINK_VISIBILITY_DEFAULT);
-    $print_mail_node_link_pages = variable_get('print_mail_node_link_pages', PRINT_MAIL_NODE_LINK_PAGES_DEFAULT);
-
-    if (!_print_page_match($print_mail_node_link_visibility, "node/" . $node->nid, $print_mail_node_link_pages)) {
-      // Page not in visibility list
-      return FALSE;
-    }
-    elseif (isset($args['type']) && ($args['type'] == 'comment') && isset($node_type)) {
-      // Link is for a comment, return the configured setting
-      // Cache this statically to avoid duplicate queries for every comment.
-      static $res = array();
-      if (!isset($res[$node->nid])) {
-        $res[$node->nid] = db_query("SELECT comments FROM {print_mail_node_conf} WHERE nid = :nid", array(':nid' => $node->nid))->fetchField();
-      }
-      $print_display_comment = ($res && ($res[$node->nid] !== FALSE)) ? $res[$node->nid] : variable_get('print_mail_display_comment_' . $node_type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-      if ($print_display_comment) {
-        return PRINT_ALLOW_NORMAL_LINK;
-      }
-    }
-    else {
-      // Node link
-      if (isset($node->print_mail_display) && !$node->print_mail_display) {
-        // Link for this node is disabled
-        return FALSE;
-      }
-      elseif (isset($node->book)) {
-        // Node is a book;
-        $print_mail_book_link = variable_get('print_mail_book_link', PRINT_MAIL_BOOK_LINK_DEFAULT);
-        switch ($print_mail_book_link) {
-          case 1:
-            if (user_access('access printer-friendly version')) {
-              return PRINT_ALLOW_BOOK_LINK;
-            }
-            break;
-          case 2:
-            return PRINT_ALLOW_NORMAL_LINK;
-        }
-      }
-      else {
-        return PRINT_ALLOW_NORMAL_LINK;
-      }
-    }
-  }
-  else {
-    // 'System' page
-    $print_mail_sys_link_visibility = variable_get('print_mail_sys_link_visibility', PRINT_MAIL_SYS_LINK_VISIBILITY_DEFAULT);
-    $print_mail_sys_link_pages = variable_get('print_mail_sys_link_pages', PRINT_MAIL_SYS_LINK_PAGES_DEFAULT);
-
-    return _print_page_match($print_mail_sys_link_visibility, $_GET['q'], $print_mail_sys_link_pages);
-  }
-  return FALSE;
+  return (user_access('access send by email'));
 }
 
 /**
@@ -650,7 +356,7 @@ function print_mail_link_allowed($args) {
  */
 function print_mail_mollom_form_list() {
   $forms['print_mail_form'] = array(
-    'title' => t('Send page form'),
+    'title' => t('Send by email form'),
     'entity' => 'print_mail',
   );
   return $forms;
@@ -666,7 +372,7 @@ function print_mail_mollom_form_info($form_id) {
         'elements' => array(
           'fld_from_addr' => t('Sender email'),
           'fld_from_name' => t('Sender name'),
-          'txt_to_addrs' => t('Recipients'),
+          'txt_to' => t('Recipients'),
           'fld_subject' => t('Subject'),
           'fld_title' => t('Page to be sent'),
           'txt_message' => t('Your message'),
@@ -729,12 +435,12 @@ function print_mail_action_submit($from, $from_name, $to, $subject, $message, $n
 
   $form_state['values'] = array(
     'path' => 'node/' . $node->nid,
-    'cid' => NULL,
     'query' => NULL,
+    'cid' => NULL,
     'title' => $node->title,
     'fld_from_addr' => $from,
     'fld_from_name' => $from_name,
-    'txt_to_addrs' => $to,
+    'txt_to' => array('addrs' => $to),
     'fld_subject' => $subject,
     'txt_message' => $message,
     'chk_teaser' => FALSE,

BIN
sites/all/modules/contrib/admin/print/print_pdf/icons/pdf_icon.png


+ 18 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/INSTALL.txt

@@ -0,0 +1,18 @@
+dompdf support:
+  The dompdf tool produces results that are more faithful to the HTML
+  printer-friendly page. Good support of CSS 2.1 and partially CSS3.
+
+  1. Download dompdf from http://code.google.com/p/dompdf/downloads/list
+  2. Extract the contents of the downloaded package into one of the
+  supported paths.
+  3. Check if dompdf_config.inc.php fits your installation. In 99% of cases,
+  no changes are necessary, so just try to use it and only edit anything if
+  the PDF generation fails.
+  4. Grant write access to the lib/fonts directory to your webserver user.
+  5. If you're using dompdf-0.5.1, delete the dompdf.php file as it contains
+  a security vulnerability
+  6. If you're using dompdf-0.6 or later, you can try to enable the Unicode
+  support, but you'll need to add some Unicode fonts. See 
+  http://groups.google.com/group/dompdf/browse_thread/thread/9f7bc0162b04d5cf
+  for further info on this.
+  7. Check http://code.google.com/p/dompdf/ for further information.

+ 38 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.admin.inc

@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains the administrative functions of the print_pdf_dompdf sub-module.
+ *
+ * This file is included by the print_pdf_dompdf module, and includes the
+ * settings form.
+ *
+ * @ingroup print
+ */
+
+/**
+ * Form constructor for the dompdf options settings form.
+ *
+ * @ingroup forms
+ */
+function print_pdf_dompdf_settings() {
+  $form['settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('dompdf options'),
+  );
+
+  $form['settings']['print_pdf_dompdf_unicode'] = array(
+    '#type' => 'checkbox',
+    '#title' => t("Use dompdf's Unicode Mode"),
+    '#default_value' => variable_get('print_pdf_dompdf_unicode', PRINT_PDF_DOMPDF_UNICODE_DEFAULT),
+    '#description' => t("If enabled, dompdf's Unicode mode is used. If not, the module will attempt to convert some non-ASCII chars to ISO-8859-1."),
+  );
+  $form['settings']['print_pdf_dompdf_font_subsetting'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable font subsetting'),
+    '#default_value' => variable_get('print_pdf_dompdf_font_subsetting', PRINT_PDF_DOMPDF_FONT_SUBSETTING_DEFAULT),
+    '#description' => t('Only embed those font characters that are actually used.  This can generates smaller PDF files but may significantly slow down processing.'),
+  );
+
+  return system_settings_form($form);
+}

+ 32 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.drush.inc

@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * drush integration for print_pdf_dompdf module PDF libraries download.
+ */
+
+/**
+ * The PDF project download URL
+ */
+
+// URI to the the latest dompdf version.. Hardcoded version unfortunately
+define('DOMPDF_DOWNLOAD_URI', 'https://github.com/dompdf/dompdf/releases/download/v0.6.1/dompdf-0.6.1.zip');
+
+/**
+ * Implements hook_drush_command().
+ */
+function print_pdf_dompdf_drush_pdf_libs_alter(&$pdf_libs) {
+  $pdf_libs['dompdf'] = array(
+    'callback' => '_print_pdf_dompdf_drush_download_url',
+  );
+}
+
+/**
+ * Discover the correct URL of the package to download.
+ *
+ * @return string
+ *   URL of the file to download, FALSE if not known
+ */
+function _print_pdf_dompdf_drush_download_url() {
+  return DOMPDF_DOWNLOAD_URI;
+}

+ 13 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.info

@@ -0,0 +1,13 @@
+name = "dompdf library handler"
+description = "PDF generation library using dompdf."
+core = 7.x
+package = "Printer, email and PDF versions"
+dependencies[] = print_pdf
+configure = admin/config/user-interface/print/pdf/dompdf
+
+; Information added by Drupal.org packaging script on 2014-04-02
+version = "7.x-2.0"
+core = "7.x"
+project = "print"
+datestamp = "1396426766"
+

+ 16 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.install

@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the print_pdf_dompdf module.
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_uninstall().
+ */
+function print_pdf_dompdf_uninstall() {
+  variable_del('print_pdf_dompdf_unicode');
+  variable_del('print_pdf_dompdf_font_subsetting');
+}

+ 95 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.module

@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Generate a PDF for the print_pdf module using the dompdf library.
+ *
+ * @ingroup print
+ */
+
+define('PRINT_PDF_DOMPDF_UNICODE_DEFAULT', 0);
+define('PRINT_PDF_DOMPDF_FONT_SUBSETTING_DEFAULT', FALSE);
+
+/**
+ * Implements hook_pdf_tool_info().
+ */
+function print_pdf_dompdf_pdf_tool_info() {
+  return array(
+    'name' => 'dompdf',
+    'url' => 'http://code.google.com/p/dompdf/downloads/list',
+    'expand_css' => FALSE,
+    'public_dirs' => array(
+      'fonts',
+    ),
+  );
+}
+
+/**
+ * Implements hook_theme().
+ */
+function print_pdf_dompdf_theme() {
+  return array(
+    'print_pdf_dompdf_footer' => array(
+      'variables' => array('html' => ''),
+      'file' => 'print_pdf_dompdf.pages.inc',
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function print_pdf_dompdf_menu() {
+  $items = array();
+
+  $items['admin/config/user-interface/print/pdf/dompdf'] = array(
+    'title' => 'dompdf',
+    'description' => 'Configure the dompdf options.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('print_pdf_dompdf_settings'),
+    'access arguments'  => array('administer print'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'print_pdf_dompdf.admin.inc',
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_pdf_tool_version().
+ */
+function print_pdf_dompdf_pdf_tool_version($pdf_tool) {
+  require_once(DRUPAL_ROOT . '/' . $pdf_tool);
+
+  // Poor man's way to find dompdf version
+  if (!defined('DOMPDF_DIR')) {
+    return 'unknown';
+  }
+  elseif (!defined('DOMPDF_CHROOT')) {
+    return '0.5.1';
+  }
+  elseif (!defined('DOMPDF_FONT_CACHE')) {
+    return '0.5.2';
+  }
+  elseif (!defined('DOMPDF_LOG_OUTPUT_FILE')) {
+    return '0.6.0 beta1';
+  }
+  elseif (!defined('DOMPDF_ADMIN_USERNAME')) {
+    return '0.6.0 beta2';
+  }
+  else {
+    return '0.6.0 beta3';
+  }
+}
+
+/**
+ * Implements hook_print_pdf_available_libs_alter().
+ */
+function print_pdf_dompdf_print_pdf_available_libs_alter(&$pdf_tools) {
+  module_load_include('inc', 'print', 'includes/print');
+  $tools = _print_scan_libs('dompdf', '!^dompdf_config.inc.php$!');
+
+  foreach ($tools as $tool) {
+    $pdf_tools['print_pdf_dompdf|' . $tool] = 'dompdf (' . dirname($tool) . ')';
+  }
+}

+ 158 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_dompdf/print_pdf_dompdf.pages.inc

@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * @file
+ * Generates the PDF version using dompdf
+ *
+ * This file is included by the print_pdf_dompdf module and includes the
+ * functions that interface with the dompdf library
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_print_pdf_generate().
+ */
+function print_pdf_dompdf_print_pdf_generate($html, $meta, $paper_size = NULL, $page_orientation = NULL) {
+  module_load_include('inc', 'print', 'includes/print');
+
+  $pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
+  if (empty($paper_size)) {
+    $paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT);
+  }
+  if (empty($page_orientation)) {
+    $page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT);
+  }
+  $content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
+  $images_via_file = variable_get('print_pdf_images_via_file', PRINT_PDF_IMAGES_VIA_FILE_DEFAULT);
+  $unicode = TRUE;
+
+  if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
+    $unicode = variable_get('print_pdf_dompdf_unicode', PRINT_PDF_DOMPDF_UNICODE_DEFAULT);
+    $font_subsetting = variable_get('print_pdf_dompdf_font_subsetting', PRINT_PDF_DOMPDF_FONT_SUBSETTING_DEFAULT);
+
+    if (!defined('DOMPDF_ENABLE_PHP')) define('DOMPDF_ENABLE_PHP', FALSE);
+    if (!defined('DOMPDF_ENABLE_REMOTE')) define('DOMPDF_ENABLE_REMOTE', TRUE);
+    if (!defined('DOMPDF_TEMP_DIR')) define('DOMPDF_TEMP_DIR', file_directory_temp());
+    if (!defined('DOMPDF_UNICODE_ENABLED')) define('DOMPDF_UNICODE_ENABLED', $unicode);
+    if (!defined('DOMPDF_ENABLE_FONTSUBSETTING')) define('DOMPDF_ENABLE_FONTSUBSETTING', $font_subsetting);
+    if (!defined('DOMPDF_FONT_CACHE')) define('DOMPDF_FONT_CACHE', drupal_realpath('public://print_pdf/print_pdf_dompdf/fonts/'));
+  }
+
+  require_once(DRUPAL_ROOT . '/' . $pdf_tool[1]);
+  spl_autoload_register('DOMPDF_autoload');
+
+  // Try to use local file access for image files
+  $html = _print_access_images_via_file($html, $images_via_file);
+
+  // Spaces in img URLs must be replaced with %20, when using external access
+  if (!$images_via_file) {
+    $pattern = '!<(img\s[^>]*?)>!is';
+    $html = preg_replace_callback($pattern, '_print_replace_spaces', $html);
+  }
+
+  // dompdf seems to have problems with something in system.css so let's not use it
+  $html = preg_replace('!<link.*?modules/system/system.css.*?/>!', '', $html);
+
+  $url_array = parse_url($meta['url']);
+
+  $protocol = $url_array['scheme'] . '://';
+  $host = $url_array['host'];
+  $path = dirname($url_array['path']) . '/';
+
+  $dompdf = new DOMPDF();
+  $dompdf->set_base_path($path);
+  $dompdf->set_host($host);
+  $dompdf->set_paper(drupal_strtolower($paper_size), $page_orientation);
+  $dompdf->set_protocol($protocol);
+
+// dompdf can't handle footers cleanly, so disable the following
+//  $html = theme('print_pdf_dompdf_footer', array('html' => $html));
+
+  // If dompdf Unicode support is disabled, try to convert to ISO-8859-1 and then to HTML entities
+  if (!$unicode) {
+    // Convert the euro sign to an HTML entity
+    $html = str_replace('€', '&#0128;', $html);
+
+    // Convert from UTF-8 to ISO 8859-1 and then to HTML entities
+    if (function_exists('utf8_decode')) {
+    $html = utf8_decode($html);
+    }
+    // iconv fails silently when it encounters something that it doesn't know, so don't use it
+//    else if (function_exists('iconv')) {
+//      $html = iconv('UTF-8', 'ISO-8859-1', $html);
+//    }
+    elseif (function_exists('mb_convert_encoding')) {
+      $html = mb_convert_encoding($html, 'ISO-8859-1', 'UTF-8');
+    }
+    elseif (function_exists('recode_string')) {
+      $html = recode_string('UTF-8..ISO_8859-1', $html);
+    }
+    $html = htmlspecialchars_decode(htmlentities($html, ENT_NOQUOTES, 'ISO-8859-1'), ENT_NOQUOTES);
+  }
+  else {
+    // Otherwise, ensure the content is properly formatted Unicode.
+    $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
+  }
+
+  // Must get rid of tbody (dompdf goes into recursion)
+  $html = preg_replace('!<tbody[^>]*?>|</tbody>!i', '', $html);
+
+  $dompdf->load_html($html);
+
+  $dompdf->render();
+  return $dompdf->output();
+}
+
+/**
+ * Format the dompdf footer contents
+ *
+ * @param array $vars
+ *   An associative array containing:
+ *    - $html: contents of the body of the HTML from the original node
+ *
+ * @return string
+ *   customized HTML text
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_pdf_dompdf_footer($vars) {
+  preg_match('!<div class="print-footer">(.*?)</div>!si', $vars['html'], $tpl_footer);
+  if (isset($tpl_footer[1])) {
+    $html = str_replace($tpl_footer[0], '', $vars['html']);
+
+    $text = '<script type="text/php">
+      if (isset($pdf)) {
+        $font = Font_Metrics::get_font("verdana");;
+        $size = 10;
+        $color = array(0,0,0);
+        $text_height = Font_Metrics::get_font_height($font, $size);
+
+        $w = $pdf->get_width();
+        $h = $pdf->get_height();
+
+        $footer = $pdf->open_object();
+
+        // Draw a line along the bottom
+        $y = $h - 25;
+        $pdf->line(15, $y, $w - 15, $y, $color, 1);
+
+        $y += $text_height / 2;
+        $pdf->page_text(15, $y, \'' . addslashes(strip_tags($tpl_footer[1])) . '\', $font, $size, $color);
+
+        $pdf->close_object();
+        $pdf->add_object($footer, "all");
+
+        // Center the text
+        $width = Font_Metrics::get_text_width("Page 1 of 2", $font, $size);
+        $pagenumtxt = t("Page !n of !total", array("!n" => "{PAGE_NUM}", "!total" => "{PAGE_COUNT}"));
+        $pdf->page_text($w - 15 - $width, $y, $pagenumtxt, $font, $size, $color);
+      }
+    </script>';
+
+    return str_replace("<body>", "<body>" . $text, $html);
+  } else {
+    return $vars['html'];
+  }
+}

+ 32 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_mpdf/print_pdf_mpdf.drush.inc

@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * drush integration for print_pdf_mpdf module PDF libraries download.
+ */
+
+/**
+ * The PDF project download URL
+ */
+
+// URI to the the latest mpdf version.. Hardcoded version unfortunately
+define('MPDF_DOWNLOAD_URI', 'http://mpdf1.com/repos/MPDF57.zip');
+
+/**
+ * Implements hook_drush_command().
+ */
+function print_pdf_mpdf_drush_pdf_libs_alter(&$pdf_libs) {
+  $pdf_libs['mpdf'] = array(
+    'callback' => '_print_pdf_mpdf_drush_download_url',
+  );
+}
+
+/**
+ * Discover the correct URL of the package to download.
+ *
+ * @return string
+ *   URL of the file to download, FALSE if not known
+ */
+function _print_pdf_mpdf_drush_download_url() {
+  return MPDF_DOWNLOAD_URI;
+}

+ 12 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_mpdf/print_pdf_mpdf.info

@@ -0,0 +1,12 @@
+name = "mPDF library handler"
+description = "PDF generation library using mPDF."
+core = 7.x
+package = "Printer, email and PDF versions"
+dependencies[] = print_pdf
+
+; Information added by Drupal.org packaging script on 2014-04-02
+version = "7.x-2.0"
+core = "7.x"
+project = "print"
+datestamp = "1396426766"
+

+ 52 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_mpdf/print_pdf_mpdf.module

@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Generate a PDF for the print_pdf module using the mPDF library.
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_pdf_tool_info().
+ */
+function print_pdf_mpdf_pdf_tool_info() {
+  return array(
+    'name' => 'mPDF',
+    'url' => 'http://www.mpdf1.com/mpdf/download',
+    'expand_css' => FALSE,
+    'public_dirs' => array(
+      'ttfontdata',
+      'tmp',
+    ),
+    'tool_dirs' => array(
+      'graph_cache',
+    ),
+  );
+}
+
+/**
+ * Implements hook_pdf_tool_version().
+ */
+function print_pdf_mpdf_pdf_tool_version($pdf_tool) {
+  require_once(DRUPAL_ROOT . '/' . $pdf_tool);
+
+  if (defined('mPDF_VERSION')) {
+    return mPDF_VERSION;
+  }
+  else {
+    return 'unknown';
+  }
+}
+
+/**
+ * Implements hook_print_pdf_available_libs_alter().
+ */
+function print_pdf_mpdf_print_pdf_available_libs_alter(&$pdf_tools) {
+  module_load_include('inc', 'print', 'includes/print');
+  $tools = _print_scan_libs('mpdf', '!^mpdf.php$!');
+
+  foreach ($tools as $tool) {
+    $pdf_tools['print_pdf_mpdf|' . $tool] = 'mPDF (' . dirname($tool) . ')';
+  }
+}

+ 65 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_mpdf/print_pdf_mpdf.pages.inc

@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Generates the PDF version using mPDF
+ *
+ * This file is included by the print_pdf_mpdf module and includes the
+ * functions that interface with the mPDF library
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_print_pdf_generate().
+ */
+function print_pdf_mpdf_print_pdf_generate($html, $meta, $paper_size = NULL, $page_orientation = NULL) {
+  module_load_include('inc', 'print', 'includes/print');
+
+  $pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
+  if (empty($paper_size)) {
+    $paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT);
+  }
+  if (empty($page_orientation)) {
+    $page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT);
+  }
+  $content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
+  $images_via_file = variable_get('print_pdf_images_via_file', PRINT_PDF_IMAGES_VIA_FILE_DEFAULT);
+
+  if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
+    if (!defined('_MPDF_TTFONTDATAPATH')) define('_MPDF_TTFONTDATAPATH', drupal_realpath('public://print_pdf/print_pdf_mpdf/ttfontdata/'));
+    if (!defined('_MPDF_TEMP_PATH')) define('_MPDF_TEMP_PATH', drupal_realpath('public://print_pdf/print_pdf_mpdf/tmp/'));
+  }
+
+  require_once(DRUPAL_ROOT . '/' . $pdf_tool[1]);
+
+  $format = ($page_orientation == "landscape") ? $paper_size . "-L" : $paper_size;
+
+  // Try to use local file access for image files
+  $html = _print_access_images_via_file($html, $images_via_file);
+
+  // set document information
+  $mpdf = new mPDF('UTF-8', $format);
+
+  $mpdf->SetAuthor(strip_tags($meta['name']));
+  $mpdf->SetCreator(variable_get('site_name', 'Drupal'));
+  // Pulled from the HTML meta data
+  // $mpdf->SetTitle(html_entity_decode($meta['title'], ENT_QUOTES, 'UTF-8'));
+
+//  $keys = implode(' ', explode("\n", trim(strip_tags($print['taxonomy']))));
+//  $mpdf->SetKeywords($keys);
+
+  // Encrypt the file and grant permissions to the user to copy and print
+  // No password is required to open the document
+  // Owner has full rights using the password "MyPassword"
+  // $mpdf->SetProtection(array('copy', 'print'), '', 'MyPassword');
+  // $mpdf->SetProtection(array('copy', 'print', 'print-highres'), '', '');
+  drupal_alter('print_pdf_mpdf', $mpdf, $html, $meta);
+
+  $mpdf->WriteHTML($html);
+
+  // try to recover from any warning/error
+  ob_clean();
+
+  return $mpdf->Output('', 'S');
+}

+ 12 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/INSTALL.txt

@@ -0,0 +1,12 @@
+TCPDF support:
+  TCPDF's support for CSS is considerably worse than the other tools.
+  Unicode is supported (use of Unicode fonts result in HUGE files).  Page
+  header and footer are supported. This module requires TCPDF >= 5.9.012.
+
+  1. Download TCPDF from http://sourceforge.net/projects/tcpdf/
+  2. Extract the contents of the downloaded package into one of the
+  supported paths.  There is no need to modify the config/tcpdf_config.php
+  file, as the module self-configures TCPDF.
+  3. Grant write access to the cache and images directories to your
+  webserver user.
+  4. Check http://tcpdf.sourceforge.net/ for further information.

+ 63 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.admin.inc

@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @file
+ * Contains the administrative functions of the print_pdf_tcpdf sub-module.
+ *
+ * This file is included by the print_pdf_tcpdf module, and includes the
+ * settings form.
+ *
+ * @ingroup print
+ */
+
+/**
+ * Form constructor for the TCPDF options settings form.
+ *
+ * @ingroup forms
+ */
+function print_pdf_tcpdf_settings() {
+  $form['settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('TCPDF options'),
+  );
+
+  $form['settings']['print_pdf_font_family'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Font family'),
+    '#default_value' => variable_get('print_pdf_font_family', PRINT_PDF_TCPDF_FONT_FAMILY_DEFAULT),
+    '#size' => 60,
+    '#maxlength' => 250,
+    '#description' => t('Set the font family to be used. Examples: %examples.', array('%examples' => 'helvetica, times, courier, dejavusans, dejavuserif, freesans, freeserif, freemono')) . '<br />' .
+                      t("CAUTION: TCPDF embeds the complete font in the generated PDF. If you're not using Unicode, then helvetica or times are safe choices that will keep the PDF small. Unicode fonts can increase the size of the PDF to the 1MB region."),
+  );
+  $form['settings']['print_pdf_font_size'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Font size'),
+    '#default_value' => variable_get('print_pdf_font_size', PRINT_PDF_TCPDF_FONT_SIZE_DEFAULT),
+    '#size' => 2,
+    '#maxlength' => 3,
+    '#description' => t('Set the font size to be used for normal text. This is the base value for the scaling applied to other text styles.'),
+  );
+  $form['settings']['print_pdf_font_subsetting'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable font subsetting'),
+    '#default_value' => variable_get('print_pdf_font_subsetting', PRINT_PDF_TCPDF_FONT_SUBSETTING_DEFAULT),
+    '#description' => t('Only embed those font characters that are actually used.  This can generates smaller PDF files but may significantly slow down processing.'),
+  );
+
+  $form['#validate'][] = '_print_pdf_tcpdf_settings_validate';
+
+  return system_settings_form($form);
+}
+
+/**
+ * Form validation handler for print_pdf_tcpdf_settings().
+ *
+ * @see print_pdf_tcpdf_settings()
+ * @ingroup forms
+ */
+function _print_pdf_tcpdf_settings_validate($form, &$form_state) {
+  if ($form_state['values']['print_pdf_font_size'] < 1) {
+    form_set_error('print_pdf_font_size', t("Font size must be at least 1."));
+  }
+}

+ 6 - 1
sites/all/modules/contrib/admin/print/print_pdf/print_pdf.class.inc → sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.class.inc

@@ -12,8 +12,13 @@
 class PrintTCPDF extends TCPDF {
   public $footer;
 
+  // Display invisible link at the bottom of all pages.
+  public function setTcpdfLink($tcpdflink) {
+    $this->tcpdflink = $tcpdflink;
+  }
+
   // Page footer data
-  public function SetFooterData($arg = '') {
+  public function setFooterContent($arg = '') {
     $this->footer = $arg;
   }
 

+ 32 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.drush.inc

@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * drush integration for print_pdf_tcpdf module PDF libraries download.
+ */
+
+/**
+ * The PDF project download URL
+ */
+
+// TCPDF is in sourceforge, and nicely provides a link to the latest version
+define('TCPDF_DOWNLOAD_URI', 'http://sourceforge.net/projects/tcpdf/files/latest');
+
+/**
+ * Implements hook_drush_command().
+ */
+function print_pdf_tcpdf_drush_pdf_libs_alter(&$pdf_libs) {
+  $pdf_libs['tcpdf'] = array(
+    'callback' => '_print_pdf_tcpdf_drush_download_url',
+  );
+}
+
+/**
+ * Discover the correct URL of the package to download.
+ *
+ * @return string
+ *   URL of the file to download, FALSE if not known
+ */
+function _print_pdf_tcpdf_drush_download_url() {
+  return TCPDF_DOWNLOAD_URI;
+}

+ 14 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.info

@@ -0,0 +1,14 @@
+name = "TCPDF library handler"
+description = "PDF generation library using TCPDF."
+core = 7.x
+package = "Printer, email and PDF versions"
+dependencies[] = print_pdf
+files[] = print_pdf_tcpdf.class.inc
+configure = admin/config/user-interface/print/pdf/tcpdf
+
+; Information added by Drupal.org packaging script on 2014-04-02
+version = "7.x-2.0"
+core = "7.x"
+project = "print"
+datestamp = "1396426766"
+

+ 17 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.install

@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the print_pdf_tcpdf module.
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_uninstall().
+ */
+function print_pdf_tcpdf_uninstall() {
+  variable_del('print_pdf_font_family');
+  variable_del('print_pdf_font_size');
+  variable_del('print_pdf_font_subsetting');
+}

+ 118 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.module

@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * @file
+ * Generate a PDF for the print_pdf module using the TCPDF library.
+ *
+ * @ingroup print
+ */
+
+define('PRINT_PDF_TCPDF_FONT_FAMILY_DEFAULT', 'dejavusans');
+define('PRINT_PDF_TCPDF_FONT_SIZE_DEFAULT', 10);
+define('PRINT_PDF_TCPDF_FONT_SUBSETTING_DEFAULT', FALSE);
+
+/**
+ * Implements hook_pdf_tool_info().
+ */
+function print_pdf_tcpdf_pdf_tool_info() {
+  return array(
+    'name' => 'TCPDF',
+    'min_version' => '5.9.001',
+    'url' => 'http://sourceforge.net/projects/tcpdf/files/latest',
+    'expand_css' => TRUE,
+    'public_dirs' => array(
+      'cache',
+    ),
+    'tool_dirs' => array(
+      'images',
+    ),
+  );
+}
+
+/**
+ * Implements hook_theme().
+ */
+function print_pdf_tcpdf_theme() {
+  return array(
+    'print_pdf_tcpdf_header' => array(
+      'variables' => array('pdf' => NULL, 'html' => '', 'font' => array()),
+      'file' => 'print_pdf_tcpdf.pages.inc',
+    ),
+    'print_pdf_tcpdf_page' => array(
+      'variables' => array('pdf' => NULL),
+      'file' => 'print_pdf_tcpdf.pages.inc',
+    ),
+    'print_pdf_tcpdf_content' => array(
+      'variables' => array('pdf' => NULL, 'html' => '', 'font' => array()),
+      'file' => 'print_pdf_tcpdf.pages.inc',
+    ),
+    'print_pdf_tcpdf_footer' => array(
+      'variables' => array('pdf' => NULL, 'html' => '', 'font' => array()),
+      'file' => 'print_pdf_tcpdf.pages.inc',
+    ),
+    'print_pdf_tcpdf_footer2' => array(
+      'variables' => array('pdf' => NULL),
+      'file' => 'print_pdf_tcpdf.pages.inc',
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function print_pdf_tcpdf_menu() {
+  $items = array();
+
+  $items['admin/config/user-interface/print/pdf/tcpdf'] = array(
+    'title' => 'TCPDF',
+    'description' => 'Configure the TCPDF options.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('print_pdf_tcpdf_settings'),
+    'access arguments'  => array('administer print'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'print_pdf_tcpdf.admin.inc',
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_pdf_tool_version().
+ */
+function print_pdf_tcpdf_pdf_tool_version($pdf_tool) {
+  if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
+    // prevent TCPDF default configs
+    define('K_TCPDF_EXTERNAL_CONFIG', TRUE);
+  }
+  require_once(DRUPAL_ROOT . '/' . $pdf_tool);
+
+  // Hide warnings, as some TCPDF constants may still be undefined
+  if (class_exists('TCPDF')) {
+    @$pdf = new TCPDF();
+
+    if (class_exists('TCPDF_STATIC')) {
+      return TCPDF_STATIC::getTCPDFVersion();
+    }
+    elseif (method_exists($pdf, 'getTCPDFVersion')) {
+      return $pdf->getTCPDFVersion();
+    }
+    elseif (defined('PDF_PRODUCER')) {
+      sscanf(PDF_PRODUCER, "TCPDF %s", $version);
+
+      return $version;
+    }
+  }
+  return 'unknown';
+}
+
+/**
+ * Implements hook_print_pdf_available_libs_alter().
+ */
+function print_pdf_tcpdf_print_pdf_available_libs_alter(&$pdf_tools) {
+  module_load_include('inc', 'print', 'includes/print');
+  $tools = _print_scan_libs('tcpdf', '!^tcpdf.php$!');
+
+  foreach ($tools as $tool) {
+    $pdf_tools['print_pdf_tcpdf|' . $tool] = 'TCPDF (' . dirname($tool) . ')';
+  }
+}

+ 285 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_tcpdf/print_pdf_tcpdf.pages.inc

@@ -0,0 +1,285 @@
+<?php
+
+/**
+ * @file
+ * Generates the PDF version using TCPDF
+ *
+ * This file is included by the print_pdf_tcpdf module and includes the
+ * functions that interface with the TCPDF library
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_print_pdf_generate().
+ */
+function print_pdf_tcpdf_print_pdf_generate($html, $meta, $paper_size = NULL, $page_orientation = NULL) {
+  global $base_url, $language;
+
+  module_load_include('inc', 'print', 'includes/print');
+
+  $pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
+  if (empty($paper_size)) {
+    $paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT);
+  }
+  if (empty($page_orientation)) {
+    $page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT);
+  }
+  $content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
+  $images_via_file = variable_get('print_pdf_images_via_file', PRINT_PDF_IMAGES_VIA_FILE_DEFAULT);
+
+  if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
+    $pdf_tool_path = realpath(dirname($pdf_tool[1]));
+
+    if (!defined('K_TCPDF_EXTERNAL_CONFIG')) define('K_TCPDF_EXTERNAL_CONFIG', TRUE);
+    if (!defined('K_PATH_MAIN')) define('K_PATH_MAIN', dirname($_SERVER['SCRIPT_FILENAME']));
+    if (!defined('K_PATH_URL')) define('K_PATH_URL', $base_url);
+    if (!defined('K_PATH_FONTS')) define('K_PATH_FONTS', $pdf_tool_path . '/fonts/');
+    if (!defined('K_PATH_CACHE')) define('K_PATH_CACHE', drupal_realpath('public://print_pdf/print_pdf_tcpdf/cache') . '/');
+    if (!defined('K_PATH_IMAGES')) define('K_PATH_IMAGES', '');
+    if (!defined('K_BLANK_IMAGE')) define('K_BLANK_IMAGE', $pdf_tool_path . '/images/_blank.png');
+    if (!defined('K_CELL_HEIGHT_RATIO')) define('K_CELL_HEIGHT_RATIO', 1.25);
+    if (!defined('K_SMALL_RATIO')) define('K_SMALL_RATIO', 2/3);
+  }
+
+  // Try to use local file access for image files
+  $html = _print_access_images_via_file($html, $images_via_file);
+
+  // Decode HTML entities in image filenames
+  $pattern = "!<img\s[^>]*?src\s*?=\s*?['\"]?{$base_url}[^>]*?>!is";
+  $html = preg_replace_callback($pattern, create_function('$matches', 'return html_entity_decode($matches[0], ENT_QUOTES);'), $html);
+  // Remove queries from the image URL
+  $pattern = "!(<img\s[^>]*?src\s*?=\s*?['\"]?{$base_url}[^>]*?)(?:%3F|\?)[^\s'\"]+([^>]*?>)!is";
+  $html = preg_replace($pattern, '$1$2', $html);
+
+  require_once(DRUPAL_ROOT . '/' . $pdf_tool[1]);
+  module_load_include('inc', 'print_pdf_tcpdf', 'print_pdf_tcpdf.class');
+
+  $font = Array(
+    check_plain(variable_get('print_pdf_font_family', PRINT_PDF_TCPDF_FONT_FAMILY_DEFAULT)),
+    '',
+    check_plain(variable_get('print_pdf_font_size', PRINT_PDF_TCPDF_FONT_SIZE_DEFAULT)),
+  );
+  $orientation = drupal_strtoupper($page_orientation[0]);
+
+  // create new PDF document
+  $pdf = new PrintTCPDF($orientation , 'mm', $paper_size, TRUE);
+
+  // set document information
+  if (isset($meta['name'])) {
+    $pdf->SetAuthor(strip_tags($meta['name']));
+  }
+  $pdf->SetCreator(variable_get('site_name', 'Drupal'));
+  $pdf->SetTitle(html_entity_decode($meta['title'], ENT_QUOTES, 'UTF-8'));
+  $pdf->setPDFVersion('1.6');
+  $pdf->setFontSubsetting(variable_get('print_pdf_font_subsetting', PRINT_PDF_TCPDF_FONT_SUBSETTING_DEFAULT));
+  $pdf->setTcpdfLink(false);
+
+  if ($language->direction == LANGUAGE_RTL) {
+    $pdf->setRTL(TRUE);
+  }
+
+  $pdf = theme('print_pdf_tcpdf_header', array('pdf' => $pdf, 'html' => $html, 'font' => $font));
+  $pdf = theme('print_pdf_tcpdf_footer', array('pdf' => $pdf, 'html' => $html, 'font' => $font));
+  $pdf = theme('print_pdf_tcpdf_page', array('pdf' => $pdf));
+
+  // Enable third-party module to alter the pdf object, via hook_print_pdf_tcpdf_alter()
+  drupal_alter('print_pdf_tcpdf', $pdf, $html, $meta);
+
+  // add a page
+  $pdf->AddPage();
+
+  $pdf = theme('print_pdf_tcpdf_content', array('pdf' => $pdf, 'html' => $html, 'font' => $font));
+
+  // reset pointer to the last page
+  $pdf->lastPage();
+
+  // try to recover from any warning/error
+  ob_clean();
+
+  return $pdf = $pdf->Output('', 'S');
+}
+
+/**
+ * Format the TCPDF header
+ *
+ * @param array $vars
+ *   An associative array containing:
+ *   - $pdf: current TCPDF object
+ *   - $html: contents of the body of the HTML from the original node
+ *   - $font: array with the font definition (font name, styles and size)
+ *
+ * @return object
+ *   modified PDF object
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_pdf_tcpdf_header($vars) {
+  global $base_url;
+
+  $pdf = $vars['pdf'];
+  preg_match('!<div class="print-logo">(.*?)</div>!si', $vars['html'], $tpl_logo);
+  preg_match('!<title>(.*?)</title>!si', $vars['html'], $tpl_title);
+  preg_match('!<div class="print-site_name">(.*?)</div>!si', $vars['html'], $tpl_site_name);
+
+  $ratio = 0;
+  $logo = '';
+  if (isset($tpl_logo[1]) && preg_match('!src\s*=\s*(?:"(.*?)"|\'(.*?)\'|([^\s]*))!i', $tpl_logo[1], $logo_url)) {
+    $logo = $logo_url[1];
+
+    // Make logo relative again
+    $logo = preg_replace("!^$base_url(.*)!sm", dirname($_SERVER['SCRIPT_FILENAME']) . '$1', $logo);
+
+    if (!empty($logo)) {
+      $size = getimagesize($logo);
+      $ratio = $size ? ($size[0] / $size[1]) : 0;
+    }
+  }
+
+  // set header font
+  $pdf->setHeaderFont($vars['font']);
+  // set header margin
+  $pdf->setHeaderMargin(5);
+  // set header data
+  $pdf->setHeaderData($logo, 10 * $ratio, html_entity_decode($tpl_title[1], ENT_QUOTES, 'UTF-8'), html_entity_decode(strip_tags($tpl_site_name[1]), ENT_QUOTES, 'UTF-8'));
+
+  return $pdf;
+}
+
+/**
+ * Format the TCPDF page settings (margins, etc)
+ *
+ * @param array $vars
+ *   An associative array containing:
+ *   - $pdf: current TCPDF object
+ *
+ * @return object
+ *   modified PDF object
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_pdf_tcpdf_page($vars) {
+  $pdf = $vars['pdf'];
+  // set margins
+  $pdf->SetMargins(15, 20, 15);
+  // set auto page breaks
+  $pdf->SetAutoPageBreak(TRUE, 15);
+  // set image scale factor
+  $pdf->setImageScale(1);
+  // set image compression quality
+  $pdf->setJPEGQuality(100);
+
+  return $pdf;
+}
+
+/**
+ * Format the TCPDF page content
+ *
+ * @param array $vars
+ *   An associative array containing:
+ *   - $pdf: current TCPDF object
+ *   - $html: contents of the body of the HTML from the original node
+ *   - $font: array with the font definition (font name, styles and size)
+ *
+ * @return object
+ *   modified PDF object
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_pdf_tcpdf_content($vars) {
+  $pdf = $vars['pdf'];
+  // set content font
+  $pdf->setFont($vars['font'][0], $vars['font'][1], $vars['font'][2]);
+
+  // Remove the logo, published, breadcrumb and footer from the main content
+  preg_match('!<body.*?>(.*)</body>!sim', $vars['html'], $matches);
+  $pattern = '!(?:<div class="print-(?:logo|site_name|breadcrumb|footer)">.*?</div>|<hr class="print-hr" />)!si';
+  $matches[1] = preg_replace($pattern, '', $matches[1]);
+
+  // Make CCK fields look better
+  $matches[1] = preg_replace('!(<div class="field.*?>)\s*!sm', '$1', $matches[1]);
+  $matches[1] = preg_replace('!(<div class="field.*?>.*?</div>)\s*!sm', '$1', $matches[1]);
+  $matches[1] = preg_replace('!<div( class="field-label.*?>.*?)</div>!sm', '<strong$1</strong>', $matches[1]);
+
+  // Since TCPDF's writeHTML is so bad with <p>, do everything possible to make it look nice
+  $matches[1] = preg_replace('!<(?:p(|\s+.*?)/?|/p)>!i', '<br$1 />', $matches[1]);
+  $matches[1] = str_replace(array('<div', 'div>'), array('<span', 'span><br />'), $matches[1]);
+  do {
+    $prev = $matches[1];
+    $matches[1] = preg_replace('!(</span>)<br />(\s*?</span><br />)!s', '$1$2', $matches[1]);
+  } while ($prev != $matches[1]);
+
+  @$pdf->writeHTML($matches[1]);
+
+  return $pdf;
+}
+
+/**
+ * Format the TCPDF footer contents
+ *
+ * @param array $vars
+ *   An associative array containing:
+ *   - $pdf: current TCPDF object
+ *   - $html: contents of the body of the HTML from the original node
+ *   - $font: array with the font definition (font name, styles and size)
+ *
+ * @return object
+ *   modified PDF object
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_pdf_tcpdf_footer($vars) {
+  $pdf = $vars['pdf'];
+  preg_match('!<div class="print-footer">(.*?)</div>!si', $vars['html'], $tpl_footer);
+
+  if (isset($tpl_footer[1])) {
+    $footer = trim(preg_replace('!</?div[^>]*?>!i', '', $tpl_footer[1]));
+
+    // set footer font
+    $vars['font'][2] *= 0.8;
+    $pdf->setFooterFont($vars['font']);
+    // set footer margin
+    $pdf->SetFooterMargin(10);
+    // set footer data
+    $pdf->setFooterContent($footer);
+  }
+
+  return $pdf;
+}
+
+/**
+ * Format the TCPDF footer layout
+ *
+ * @param array $vars
+ *   An associative array containing:
+ *   - $pdf: current TCPDF object
+ *
+ * @return object
+ *   modified PDF object
+ *
+ * @ingroup themeable
+ * @ingroup print_themeable
+ */
+function theme_print_pdf_tcpdf_footer2($vars) {
+  $pdf = $vars['pdf'];
+  // Position at 1.5 cm from bottom
+  $pdf->writeHTMLCell(0, 15, 15, $pdf->getPageHeight()-15, $pdf->footer);
+
+  $ormargins = $pdf->getOriginalMargins();
+  $pagenumtxt = t('Page !n of !total', array('!n' => $pdf->PageNo(), '!total' => $pdf->getAliasNbPages()));
+  // Print page number
+  if ($pdf->getRTL()) {
+    $pdf->SetX($ormargins['right']);
+    $pdf->Cell(0, 10, $pagenumtxt, 'T', 0, 'L');
+  }
+  else {
+    $pdf->SetX($ormargins['left']);
+    $pdf->Cell(0, 10, $pagenumtxt, 'T', 0, 'R');
+  }
+
+  return $pdf;
+}

+ 17 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/INSTALL.txt

@@ -0,0 +1,17 @@
+wkhtmltopdf support:
+  wkhtmltopdf is a webkit-based tool that actually is a browser in order to
+  generate the PDF.  Resource hungry: expect to need some 30Mb+ of RAM and
+  some seconds of CPU power.  The static binaries may need additional
+  libraries in your site, which may present problems in shared hosting
+  environments.  The best, if you can run it.
+
+  1. Download wkhtmltopdf from
+  http://code.google.com/p/wkhtmltopdf/downloads/list. You can choose to
+  download the source and compile it or simply download the static binary,
+  which doesn't require you to compile anything. Note that the compiled
+  version may require a running X server (static uses patched libs that can
+  work without one).
+  2. Place the wkhtmltopdf executable into one of the supported paths. 
+  (usually sites/all/modules/print/lib).  You can also place a symbolic link
+  to the executable.
+  3. Check http://code.google.com/p/wkhtmltopdf/ for further information.

+ 47 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.admin.inc

@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Contains the administrative functions of the print_pdf_wkhtmltopdf module.
+ *
+ * This file is included by the print_pdf_wkhtmltopdf module, and includes the
+ * settings form.
+ *
+ * @ingroup print
+ */
+
+/**
+ * Form constructor for the wkhtmltopdf options settings form.
+ *
+ * @ingroup forms
+ */
+function print_pdf_wkhtmltopdf_settings() {
+  $form['settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('wkhtmltopdf options'),
+  );
+
+  $form['settings']['print_pdf_wkhtmltopdf_options'] = array(
+    '#type' => 'textfield',
+    '#title' => t('wkhtmltopdf options'),
+    '#size' => 60,
+    '#maxlength' => 500,
+    '#default_value' => variable_get('print_pdf_wkhtmltopdf_options', PRINT_PDF_WKHTMLTOPDF_OPTIONS),
+    '#description' => t('(wkhtmltopdf only) Set any additional options to be passed to the wkhtmltopdf executable. Tokens may be used in these options (see list below).'),
+  );
+
+  if (module_exists('token')) {
+    $form['settings']['print_pdf_filename_patterns'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Replacement patterns'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+    $form['settings']['print_pdf_filename_patterns']['descriptions'] = array(
+      '#theme' => 'token_tree',
+      '#token_types' => array('node'),
+    );
+  }
+
+  return system_settings_form($form);
+}

+ 53 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.drush.inc

@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * @file
+ * drush integration for print_pdf_wkhtmltopdf module PDF libraries download.
+ */
+
+/**
+ * The PDF project download URL
+ */
+
+// wkhtmltopdf is a binary, requiring a different download for each platform
+define('WKHTMLTOPDF_AMD64_DOWNLOAD_URI', 'http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.0/wkhtmltox-linux-amd64_0.12.0-03c001d.tar.xz');
+define('WKHTMLTOPDF_I386_DOWNLOAD_URI', 'http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.0/wkhtmltox-linux-i386_0.12.0-03c001d.tar.xz');
+define('WKHTMLTOPDF_WIN64_DOWNLOAD_URI', 'http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.0/wkhtmltox-win64_0.12.0-03c001d.exe');
+define('WKHTMLTOPDF_WIN_DOWNLOAD_URI', 'http://downloads.sourceforge.net/project/wkhtmltopdf/0.12.0/wkhtmltox-win32_0.12.0-03c001d.exe');
+define('WKHTMLTOPDF_OSX_DOWNLOAD_URI', 'http://wkhtmltopdf.googlecode.com/files/wkhtmltopdf-OSX-0.10.0_rc2-static.tar.bz2');
+
+/**
+ * Implements hook_drush_command().
+ */
+function print_pdf_wkhtmltopdf_drush_pdf_libs_alter(&$pdf_libs) {
+  $pdf_libs['wkhtmltopdf'] = array(
+    'callback' => '_print_pdf_wkhtmltopdf_drush_download_url',
+  );
+}
+
+/**
+ * Discover the correct URL of the package to download.
+ *
+ * @return string
+ *   URL of the file to download, FALSE if not known
+ */
+function _print_pdf_wkhtmltopdf_drush_download_url() {
+  $ret = FALSE;
+
+  switch (drupal_substr(php_uname('s'), 0, 3)) {
+    case 'Lin':
+      $ret = (php_uname('m') == 'x86_64') ? WKHTMLTOPDF_AMD64_DOWNLOAD_URI : WKHTMLTOPDF_I386_DOWNLOAD_URI;
+      break;
+    case 'Win':
+      $ret = WKHTMLTOPDF_WIN_DOWNLOAD_URI;
+      break;
+    case 'Dar':
+      $ret = WKHTMLTOPDF_OSX_DOWNLOAD_URI;
+      break;
+    default:
+      drush_log(dt('wkhtmltopdf is not supported in this system, please choose another library.'), 'error');
+      break;
+  }
+
+  return $ret;
+}

+ 13 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.info

@@ -0,0 +1,13 @@
+name = "wkhtmltopdf library handler"
+description = "PDF generation library using wkhtmltopdf."
+core = 7.x
+package = "Printer, email and PDF versions"
+dependencies[] = print_pdf
+configure = admin/config/user-interface/print/pdf/wkhtmltopdf
+
+; Information added by Drupal.org packaging script on 2014-04-02
+version = "7.x-2.0"
+core = "7.x"
+project = "print"
+datestamp = "1396426766"
+

+ 15 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.install

@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the print_pdf_wkhtmltopdf module.
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_uninstall().
+ */
+function print_pdf_wkhtmltopdf_uninstall() {
+  variable_del('print_pdf_wkhtmltopdf_options');
+}

+ 106 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.module

@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * @file
+ * Generate a PDF for the print_pdf module using the wkhtmltopdf library.
+ *
+ * @ingroup print
+ */
+
+define('PRINT_PDF_WKHTMLTOPDF_OPTIONS', "--footer-font-size 7 --footer-right '[page]'");
+
+/**
+ * Implements hook_pdf_tool_info().
+ */
+function print_pdf_wkhtmltopdf_pdf_tool_info() {
+  return array(
+    'name' => 'wkhtmltopdf',
+    'min_version' => '0.9.6',
+    'url' => 'http://code.google.com/p/wkhtmltopdf/downloads/list',
+    'expand_css' => FALSE,
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function print_pdf_wkhtmltopdf_menu() {
+  $items = array();
+
+  $items['admin/config/user-interface/print/pdf/wkhtmltopdf'] = array(
+    'title' => 'wkhtmltopdf',
+    'description' => 'Configure the wkhtmltopdf options.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('print_pdf_wkhtmltopdf_settings'),
+    'access arguments'  => array('administer print'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'print_pdf_wkhtmltopdf.admin.inc',
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_requirements().
+ */
+function print_pdf_wkhtmltopdf_requirements($phase) {
+  $requirements = array();
+  $t = get_t();
+  switch ($phase) {
+    // At runtime, make sure that a PDF generation tool is selected
+    case 'runtime':
+      $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
+      if (!empty($print_pdf_pdf_tool)) {
+        $tool = explode('|', $print_pdf_pdf_tool);
+
+        if (is_file($tool[1]) && is_readable($tool[1])) {
+          if (drupal_substr(basename($tool[1], '.exe'), 0, 11) == 'wkhtmltopdf') {
+            if (function_exists('is_executable') && !is_executable($tool[1])) {
+              $requirements['print_pdf_wkhtmltopdf'] = array(
+                'title' => $t('wkhtmltopdf library'),
+                'value' => $t('Non-executable permissions'),
+                'description' => $t('You must modify the permissions of the wkhtmltopdf file (%file) to make it executable.', array('%file' => $tool[1])),
+                'severity' => REQUIREMENT_ERROR,
+              );
+            }
+          }
+        }
+      }
+      break;
+  }
+  return $requirements;
+}
+
+/**
+ * Implements hook_pdf_tool_version().
+ */
+function print_pdf_wkhtmltopdf_pdf_tool_version($pdf_tool) {
+  $descriptor = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
+
+  $cmd = '"' . realpath($pdf_tool) . '" --version';
+  $process = proc_open($cmd, $descriptor, $pipes, NULL, NULL);
+  if (is_resource($process)) {
+    $content = stream_get_contents($pipes[1]);
+    $out = preg_match('!.*?(\d+\.\d+\.\d+).*$!m', $content, $matches);
+    fclose($pipes[0]);
+    fclose($pipes[1]);
+    fclose($pipes[2]);
+    $retval = proc_close($process);
+  }
+
+  return ($matches[1]);
+}
+
+/**
+ * Implements hook_print_pdf_available_libs_alter().
+ */
+function print_pdf_wkhtmltopdf_print_pdf_available_libs_alter(&$pdf_tools) {
+  module_load_include('inc', 'print', 'includes/print');
+  $tools = _print_scan_libs('wkhtmltopdf', '!^wkhtmltopdf!');
+
+  foreach ($tools as $tool) {
+    $version = print_pdf_wkhtmltopdf_pdf_tool_version($tool);
+
+    $pdf_tools['print_pdf_wkhtmltopdf|' . $tool] = 'wkhtmltopdf ' . $version . ' (' . $tool . ')';
+  }
+}

+ 85 - 0
sites/all/modules/contrib/admin/print/print_pdf/lib_handlers/print_pdf_wkhtmltopdf/print_pdf_wkhtmltopdf.pages.inc

@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * @file
+ * Generates the PDF version using wkhtmltopdf
+ *
+ * This file is included by the print_pdf_wkhtmltopdf module and includes the
+ * functions that interface with the wkhtmltopdf library
+ *
+ * @ingroup print
+ */
+
+/**
+ * Implements hook_print_pdf_generate().
+ */
+function print_pdf_wkhtmltopdf_print_pdf_generate($html, $meta, $paper_size = NULL, $page_orientation = NULL) {
+  $pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
+  if (empty($paper_size)) {
+    $paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT);
+  }
+  if (empty($page_orientation)) {
+    $page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT);
+  }
+  $content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
+  $wkhtmltopdf_options = variable_get('print_pdf_wkhtmltopdf_options', PRINT_PDF_WKHTMLTOPDF_OPTIONS);
+
+  $dpi = 96;
+
+  if (!empty($wkhtmltopdf_options) && isset($meta['node'])) {
+    $wkhtmltopdf_options = token_replace($wkhtmltopdf_options, array('node' => $meta['node']), array('clear' => TRUE));
+  }
+
+  $version = print_pdf_wkhtmltopdf_pdf_tool_version($pdf_tool[1]);
+
+  // 0.10.0 beta2 identifies itself as 0.9.9
+  if (version_compare($version, '0.9.9', '>=')) {
+    $wkhtmltopdf_options = '--disable-local-file-access ' . $wkhtmltopdf_options;
+  }
+  elseif (version_compare($version, '0.9.6', '>=')) {
+    $wkhtmltopdf_options = '--disallow-local-file-access ' . $wkhtmltopdf_options;
+  }
+  else {
+    drupal_goto($meta['url']);
+    exit;
+  }
+
+  // use basic http authentication to fetch included CSS, etc
+  if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
+    $wkhtmltopdf_options .= ' --username ' . check_plain($_SERVER['PHP_AUTH_USER']) . ' --password ' . check_plain($_SERVER['PHP_AUTH_PW']);
+  }
+
+  $descriptor = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'a'));
+  $cmd = '"' . realpath($pdf_tool[1]) . "\" --page-size $paper_size --orientation $page_orientation --dpi $dpi $wkhtmltopdf_options - -";
+
+  $process = proc_open($cmd, $descriptor, $pipes, NULL, NULL);
+
+  if (is_resource($process)) {
+    fwrite($pipes[0], $html);
+    fclose($pipes[0]);
+
+    $pdf = stream_get_contents($pipes[1]);
+    fclose($pipes[1]);
+
+    stream_set_blocking($pipes[2], 0);
+    $error = stream_get_contents($pipes[2]);
+    fclose($pipes[2]);
+
+    $retval = proc_close($process);
+    if (!empty($error) || ($retval != 0)) {
+      if (empty($error)) {
+        $error = 'No stderr output available.';
+      }
+      watchdog('print_pdf', 'wkhtmltopdf [%cmd] (returned %ret): %error', array('%cmd' => $cmd, '%ret' => $retval, '%error' => $error));
+    }
+  }
+
+  if (!empty($pdf)) {
+    return $pdf;
+  }
+  else {
+    drupal_set_message(t('Unable to generate PDF file.'), 'error');
+    drupal_goto($meta['url']);
+    return NULL;
+  }
+}

+ 68 - 240
sites/all/modules/contrib/admin/print/print_pdf/print_pdf.admin.inc

@@ -11,17 +11,20 @@
  */
 
 /**
- * Menu callback for the PDF version module settings form.
+ * Form constructor for the PDF version module settings form.
  *
  * @ingroup forms
- * @see _print_pdf_tools()
  */
 function print_pdf_settings() {
-  $pdf_tools = _print_pdf_tools();
-  $current_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
-  $pdf_tool_default = (in_array($current_pdf_tool, $pdf_tools)) ? $current_pdf_tool : PRINT_PDF_PDF_TOOL_DEFAULT;
+  $pdf_tools = array();
+  drupal_alter('print_pdf_available_libs', $pdf_tools);
+
+  if (!empty($pdf_tools)) {
+    $link = print_pdf_print_link();
+
+    $current_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
+    $pdf_tool_default =  array_key_exists($current_pdf_tool, $pdf_tools) ? $current_pdf_tool : PRINT_PDF_PDF_TOOL_DEFAULT;
 
-  if ($pdf_tools != -1) {
     $form['settings'] = array(
       '#type' => 'fieldset',
       '#title' => t('PDF options'),
@@ -35,113 +38,6 @@ function print_pdf_settings() {
       '#description' => t('This option selects the PDF generation tool being used by this module to create the PDF version.'),
     );
 
-    $form['settings']['print_pdf_link_pos'] = array(
-      '#type' => 'checkboxes',
-      '#title' => t('PDF version link'),
-      '#default_value' => variable_get('print_pdf_link_pos', drupal_json_decode(PRINT_PDF_LINK_POS_DEFAULT)),
-      '#options' => array('link' => t('Links area'), 'corner' => t('Content corner'), 'block' => t('Block'), 'help' => t('Help area')),
-      '#description' => t('Choose the location of the link(s) to the PDF version. The Links area is usually below the node content, whereas the Content corner is placed in the upper-right corner of the node content. Unselect all options to disable the link. Even if the link is disabled, you can still view the PDF version of a node by going to !path/nid where nid is the numeric id of the node.', array('!path' => PRINTPDF_PATH)),
-    );
-
-    $form['settings']['print_pdf_link_teaser'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Display link to the PDF version in teaser'),
-      '#default_value' => variable_get('print_pdf_link_teaser', PRINT_PDF_LINK_TEASER_DEFAULT),
-      '#description' => t('Enabling this will display the link in teaser mode.'),
-    );
-
-    $form['settings']['adv_link'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Advanced link options'),
-      '#collapsible' => TRUE,
-      '#collapsed' => FALSE,
-    );
-
-    $form['settings']['adv_link']['print_pdf_show_link'] = array(
-      '#type' => 'radios',
-      '#title' => t('Link style'),
-      '#default_value' => variable_get('print_pdf_show_link', PRINT_PDF_SHOW_LINK_DEFAULT),
-      '#options' => array(1 => t('Text only'), 2 => t('Icon only'), 3 => t('Icon and Text')),
-      '#description' => t('Select the visual style of the link.'),
-    );
-
-    $form['settings']['adv_link']['print_pdf_link_use_alias'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Use URL alias instead of node ID'),
-      '#default_value' => variable_get('print_pdf_link_use_alias', PRINT_PDF_LINK_USE_ALIAS_DEFAULT),
-      '#description' => t('Enabling this will create the link using the URL alias instead of the node ID.'),
-    );
-
-    $form['settings']['adv_link']['print_pdf_link_class'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Link class'),
-      '#default_value' => variable_get('print_pdf_link_class', PRINT_PDF_LINK_CLASS_DEFAULT),
-      '#size' => 60,
-      '#maxlength' => 250,
-      '#description' => t('This can be used by themers to change the link style or by jQuery modules to open in a new window (e.g. greybox or thickbox). Multiple classes can be specified, separated by spaces.'),
-    );
-
-    $form['settings']['adv_link']['print_pdf_node_link_visibility'] = array(
-      '#type' => 'radios',
-      '#title' => t('Link visibility'),
-      '#default_value' => variable_get('print_pdf_node_link_visibility', PRINT_PDF_NODE_LINK_VISIBILITY_DEFAULT),
-      '#options' => array(t('Show on every page except the listed pages.'), t('Show on only the listed pages.')),
-    );
-
-    $form['settings']['adv_link']['print_pdf_node_link_pages'] = array(
-      '#type' => 'textarea',
-      '#default_value' => variable_get('print_pdf_node_link_pages', PRINT_PDF_NODE_LINK_PAGES_DEFAULT),
-      '#rows' => 3,
-      '#description' => t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>')),
-    );
-
-    if (module_exists('php')) {
-      $access = user_access('use PHP for settings');
-
-      if ($form['settings']['adv_link']['print_pdf_node_link_visibility']['#default_value'] == 2 && !$access) {
-        $form['settings']['adv_link']['print_pdf_node_link_visibility'] = array('#type' => 'value', '#value' => 2);
-        $form['settings']['adv_link']['print_pdf_node_link_pages'] = array('#type' => 'value', '#value' => $form['settings']['adv_link']['print_pdf_node_link_pages']['#default_value']);
-      }
-      elseif ($access) {
-        $form['settings']['adv_link']['print_pdf_node_link_visibility']['#options'][] = t('Show if the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
-        $form['settings']['adv_link']['print_pdf_node_link_pages']['#description'] .= ' ' . t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can break your Drupal site.', array('%php' => '<?php ?>'));
-      }
-    }
-
-    $form['settings']['adv_link']['print_pdf_sys_link_visibility'] = array(
-      '#type' => 'radios',
-      '#title' => t('Show link in system (non-content) pages'),
-      '#description' => 'Any page that is not a Drupal node. Usually pages generated by Drupal or a module such as Views or Panels.',
-      '#default_value' => variable_get('print_pdf_sys_link_visibility', PRINT_PDF_SYS_LINK_VISIBILITY_DEFAULT),
-      '#options' => array(t('Show on every page except the listed pages.'), t('Show on only the listed pages.')),
-    );
-
-    $form['settings']['adv_link']['print_pdf_sys_link_pages'] = array(
-      '#type' => 'textarea',
-      '#default_value' => variable_get('print_pdf_sys_link_pages', PRINT_PDF_SYS_LINK_PAGES_DEFAULT),
-      '#rows' => 3,
-      '#description' => t('Setting this option will add a PDF version page link on pages created by Drupal or the enabled modules.') . '<br />' .
-                        t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>')),
-    );
-
-    if (module_exists('php')) {
-      if ($form['settings']['adv_link']['print_pdf_sys_link_visibility']['#default_value'] == 2 && !$access) {
-        $form['settings']['adv_link']['print_pdf_sys_link_visibility'] = array('#type' => 'value', '#value' => 2);
-        $form['settings']['adv_link']['print_pdf_sys_link_pages'] = array('#type' => 'value', '#value' => $form['settings']['adv_link']['print_pdf_sys_link_pages']['#default_value']);
-      }
-      elseif ($access) {
-        $form['settings']['adv_link']['print_pdf_sys_link_visibility']['#options'][] = t('Show if the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
-        $form['settings']['adv_link']['print_pdf_sys_link_pages']['#description'] .= ' ' . t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can break your Drupal site.', array('%php' => '<?php ?>'));
-      }
-    }
-
-    $form['settings']['adv_link']['print_pdf_book_link'] = array(
-      '#type' => 'radios',
-      '#title' => t('Link in book hierarchy nodes'),
-      '#default_value' => variable_get('print_pdf_book_link', PRINT_PDF_BOOK_LINK_DEFAULT),
-      '#options' => array(t('No link'), t('Current page and sub-pages'), t('Current page only')),
-    );
-
     $form['settings']['print_pdf_content_disposition'] = array(
       '#type' => 'radios',
       '#title' => t('Open PDF in'),
@@ -153,21 +49,7 @@ function print_pdf_settings() {
     $form['settings']['print_pdf_paper_size'] = array(
       '#type' => 'select',
       '#title' => t('Paper size'),
-      '#options' => array('4A0' => '4A0', '2A0' => '2A0', 'A0' => 'A0',
-                          'A1' => 'A1', 'A2' => 'A2', 'A3' => 'A3', 'A4' => 'A4',
-                          'A5' => 'A5', 'A6' => 'A6', 'A7' => 'A7', 'A8' => 'A8',
-                          'A9' => 'A9', 'A10' => 'A10', 'B0' => 'B0', 'B1' => 'B1',
-                          'B2' => 'B2', 'B3' => 'B3', 'B4' => 'B4', 'B5' => 'B5',
-                          'B6' => 'B6', 'B7' => 'B7', 'B8' => 'B8', 'B9' => 'B9',
-                          'B10' => 'B10', 'C0' => 'C0', 'C1' => 'C1', 'C2' => 'C2',
-                          'C3' => 'C3', 'C4' => 'C4', 'C5' => 'C5', 'C6' => 'C6',
-                          'C7' => 'C7', 'C8' => 'C8', 'C9' => 'C9', 'C10' => 'C10',
-                          'RA0' => 'RA0', 'RA1' => 'RA1', 'RA2' => 'RA2',
-                          'RA3' => 'RA3', 'RA4' => 'RA4', 'SRA0' => 'SRA0',
-                          'SRA1' => 'SRA1', 'SRA2' => 'SRA2', 'SRA3' => 'SRA3',
-                          'SRA4' => 'SRA4', 'LETTER' => 'Letter', 'LEGAL' => 'Legal',
-                          'EXECUTIVE' => 'Executive', 'FOLIO' => 'Folio',
-                    ),
+      '#options' => _print_pdf_paper_sizes(),
       '#default_value' => variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT),
       '#description' => t('Choose the paper size of the generated PDF.'),
     );
@@ -179,6 +61,35 @@ function print_pdf_settings() {
       '#default_value' => variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT),
       '#description' => t('Choose the page orientation of the generated PDF.'),
     );
+
+    $form['settings']['print_pdf_cache_enabled'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable caching of generated PDFs'),
+      '#default_value' => variable_get('print_pdf_cache_enabled', PRINT_PDF_CACHE_ENABLED_DEFAULT),
+    );
+
+    $form['settings']['print_pdf_cache_lifetime'] = array(
+      '#type' => 'select',
+      '#title' => t('Cache Lifetime'),
+      '#options' => array(
+        '0'      => 'None',
+        '10800'  => '3 hours',
+        '21600'  => '6 hours',
+        '43200'  => '12 hours',
+        '64800'  => '18 hours',
+        '86400'  => '24 hours',
+        '129600' => '36 hours',
+        '172800' => '2 days',
+        '259200' => '3 days',
+        '345600' => '4 days',
+        '432000' => '5 days',
+        '518400' => '6 days',
+        '604800' => '7 days',
+      ),
+      '#default_value' => variable_get('print_pdf_cache_lifetime', PRINT_PDF_CACHE_LIFETIME_DEFAULT),
+      '#description' => t('The lifetime of cached PDFs. A cached PDF is only removed when a node is updated, deleted, or cron is run and the last access is older than this value.'),
+    );
+
     $form['settings']['print_pdf_images_via_file'] = array(
       '#type' => 'checkbox',
       '#title' => t('Access images via local file access'),
@@ -191,50 +102,13 @@ function print_pdf_settings() {
       '#default_value' => variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT),
       '#description' => t('If you disable this option, the pdf tool settings must be configured manually. For TCDPF, edit the tcpdf/config/tcpdf_config.php file. For dompdf, edit the dompdf/dompdf_config.inc.php file.'),
     );
-    $form['settings']['print_pdf_font_family'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Font family'),
-      '#default_value' => variable_get('print_pdf_font_family', PRINT_PDF_FONT_FAMILY_DEFAULT),
-      '#size' => 60,
-      '#maxlength' => 250,
-      '#description' => t('(TCPDF only) Set the font family to be used. Examples: %examples.', array('%examples' => 'helvetica, times, courier, dejavusans, dejavuserif, freesans, freeserif, freemono')) . '<br />' .
-                        t("CAUTION: TCPDF embeds the complete font in the generated PDF. If you're not using Unicode, then helvetica or times are safe choices that will keep the PDF small. Unicode fonts can increase the size of the PDF to the 1MB region."),
-    );
-    $form['settings']['print_pdf_font_size'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Font size'),
-      '#default_value' => variable_get('print_pdf_font_size', PRINT_PDF_FONT_SIZE_DEFAULT),
-      '#size' => 2,
-      '#maxlength' => 3,
-      '#description' => t('(TCPDF only) Set the font size to be used for normal text. This is the base value for the scaling applied to other text styles.'),
-    );
-    $form['settings']['print_pdf_font_subsetting'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Enable font subsetting'),
-      '#default_value' => variable_get('print_pdf_font_subsetting', PRINT_PDF_FONT_SUBSETTING_DEFAULT),
-      '#description' => t('(TCPDF only) Only embed those font characters that are actually used.  This can generates smaller PDF files but may significantly slow down processing.'),
-    );
-    $form['settings']['print_pdf_dompdf_unicode'] = array(
-      '#type' => 'checkbox',
-      '#title' => t("Use dompdf's Unicode Mode"),
-      '#default_value' => variable_get('print_pdf_dompdf_unicode', PRINT_PDF_DOMPDF_UNICODE_DEFAULT),
-      '#description' => t("If enabled, dompdf's Unicode mode is used. If not, the module will attempt to convert some non-ASCII chars to ISO-8859-1."),
-    );
-    $form['settings']['print_pdf_wkhtmltopdf_options'] = array(
+
+    $form['settings']['print_pdf_filename'] = array(
       '#type' => 'textfield',
-      '#title' => t('wkhtmltopdf options'),
-      '#size' => 60,
-      '#maxlength' => 500,
-      '#default_value' => variable_get('print_pdf_wkhtmltopdf_options', PRINT_PDF_WKHTMLTOPDF_OPTIONS),
-      '#description' => t('(wkhtmltopdf only) Set any additional options to be passed to the wkhtmltopdf executable. Tokens may be used in these options (see list below).'),
+      '#title' => t('PDF filename'),
+      '#default_value' => variable_get('print_pdf_filename', PRINT_PDF_FILENAME_DEFAULT),
+      '#description' => t("If left empty the generated filename defaults to the node's path. Tokens may be used to build the filename (see following list). The .pdf extension will be appended automatically."),
     );
-
-      $form['settings']['print_pdf_filename'] = array(
-        '#type' => 'textfield',
-        '#title' => t('PDF filename'),
-        '#default_value' => variable_get('print_pdf_filename', PRINT_PDF_FILENAME_DEFAULT),
-        '#description' => t("If left empty the generated filename defaults to the node's path. Tokens may be used to build the filename (see following list). The .pdf extension will be appended automatically."),
-      );
     if (module_exists('token')) {
       $form['settings']['print_pdf_filename_patterns'] = array(
         '#type' => 'fieldset',
@@ -255,12 +129,31 @@ function print_pdf_settings() {
       '#description' => t('Enabling this option will display a list of printer-friendly destination URLs at the bottom of the page.'),
     );
 
+    $form['settings']['link_text'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Custom link text'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+    $form['settings']['link_text']['print_pdf_link_text_enabled'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable custom link text'),
+      '#default_value' => variable_get('print_pdf_link_text_enabled', PRINT_TYPE_LINK_TEXT_ENABLED_DEFAULT),
+    );
+    $form['settings']['link_text']['print_pdf_link_text'] = array(
+      '#type' => 'textfield',
+      '#default_value' => variable_get('print_pdf_link_text', $link['text']),
+      '#description' => t('Text used in the link to the PDF version.'),
+    );
+
     $form['#validate'][] = '_print_pdf_settings_validate';
   }
   else {
+    variable_set('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
+
     $form['settings'] = array(
       '#type' => 'markup',
-      '#markup' => '<p>' . t("No PDF generation tool found! Please dowload a supported PHP PDF generation tool. Check this module's INSTALL.txt for more details.") . '</p>',
+      '#markup' => '<p>' . t("No PDF generation tool found! Please download a supported PHP PDF generation tool. Check this module's INSTALL.txt for more details.") . '</p>',
     );
   }
 
@@ -268,78 +161,13 @@ function print_pdf_settings() {
 }
 
 /**
- * Validate print_pdf_settings form.
+ * Form validation handler for print_pdf_settings().
+ *
+ * @see print_pdf_settings()
+ * @ingroup forms
  */
 function _print_pdf_settings_validate($form, &$form_state) {
   if (empty($form_state['values']['print_pdf_pdf_tool'])) {
     form_set_error('print_pdf_pdf_tool', t("No PDF tool selected"));
   }
-  if ($form_state['values']['print_pdf_font_size'] < 1) {
-    form_set_error('print_pdf_font_size', t("Font size must be at least 1."));
-  }
-}
-
-/**
- * Auxiliary function to locate suitable PDF generation tools
- *
- * @return
- *   array of filenames with the include-able PHP file of the located tools
- */
-function _print_pdf_tools() {
-  $pattern = '!^(?:dompdf_config.inc.php|tcpdf.php|wkhtmltopdf.*)$!';
-  $tools = array_keys(file_scan_directory(drupal_get_path('module', 'print'), $pattern));
-  $tools = array_merge($tools, array_keys(file_scan_directory(PRINT_PDF_LIB_PATH, $pattern)));
-  if (module_exists('libraries')) {
-    $tools = array_merge($tools, array_keys(file_scan_directory(libraries_get_path('dompdf'), '/^dompdf_config.inc.php$/')));
-    $tools = array_merge($tools, array_keys(file_scan_directory(libraries_get_path('tcpdf'), '/^tcpdf.php$/')));
-    $tools = array_merge($tools, array_keys(file_scan_directory(libraries_get_path('wkhtmltopdf'), '/^wkhtmltopdf/')));
-  }
-
-
-  $num_tools = count($tools);
-
-  if ($num_tools == 0) {
-    variable_set('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
-    return -1;
-  }
-  else {
-    return array_combine($tools, $tools);
-  }
-}
-
-/**
- * Menu callback for the PDF version module text strings settings form.
- *
- * @ingroup forms
- */
-function print_pdf_strings_settings() {
-  drupal_set_message(t("Saving these strings will disable their translation via Drupal's language system. Use the reset button to return them to the original state."), 'warning');
-
-  $form['print_pdf_text'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Text strings'),
-  );
-
-  $form['print_pdf_text']['print_pdf_link_text'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Link text'),
-    '#default_value' => variable_get('print_pdf_link_text', t('PDF version')),
-    '#description' => t('Text used in the link to the PDF version.'),
-  );
-  $form['print_pdf_text']['reset'] = array(
-    '#type' => 'submit',
-    '#value' => t('Reset to defaults'),
-    '#submit' => array('print_pdf_strings_settings_delete'),
-  );
-
-  return system_settings_form($form);
-}
-
-/**
- * Reset button callback for text strings settings form
- *
- * @ingroup forms
- */
-function print_pdf_strings_settings_delete() {
-  variable_del('print_pdf_link_text');
 }

+ 144 - 0
sites/all/modules/contrib/admin/print/print_pdf/print_pdf.api.php

@@ -0,0 +1,144 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the PDF version module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Provide some information on the needs of the PDF library.
+ *
+ * @return
+ *   Associative array with the following data:
+ *   - name: name of the PDF library.
+ *   - min_version: minimum version of the PDF library supported by the
+ *     module.
+ *   - url: URL where the PDF library can be downloaded from.
+ *   - expand_css: boolean flag indicating whether to expand the CSS files
+ *     in the HTML passed to the PDF library, or to leave it as a list of
+ *     include directives.
+ *   - public_dirs: directories to which the tool requires write-access,
+ *     with configurable locations.
+ *   - tool_dirs: directories to which the tool requires write-access, but
+ *     can't be configured, and are relative to the tool's root path.
+ *
+ * @ingroup print_hooks
+ */
+function hook_pdf_tool_info() {
+  return array(
+    'name' => 'foopdf',
+    'min_version' => '1.0',
+    'url' => 'http://www.pdf.tool/download',
+    'expand_css' => FALSE,
+    'public_dirs' => array(
+      'fonts',
+      'cache',
+      'tmp',
+    ),
+    'tool_dirs' => array(
+      'xyz',
+    ),
+  );
+}
+
+/**
+ * Find out the version of the PDF library
+ *
+ * @param string $pdf_tool
+ *   Filename of the tool to be analysed.
+ *
+ * @return string
+ *   version number of the library
+ */
+function hook_pdf_tool_version() {
+  require_once(DRUPAL_ROOT . '/' . $pdf_tool);
+
+  return '1.0';
+}
+
+/**
+ * Generate a PDF version of the provided HTML.
+ *
+ * @param string $html
+ *   HTML content of the PDF
+ * @param array $meta
+ *   Meta information to be used in the PDF
+ *   - url: original URL
+ *   - name: author's name
+ *   - title: Page title
+ *   - node: node object
+ * @param string $paper_size
+ *   (optional) Paper size of the generated PDF
+ * @param string $page_orientation
+ *   (optional) Page orientation of the generated PDF
+ *
+ * @return
+ *   generated PDF page, or NULL in case of error
+ *
+ * @see print_pdf_controller_html()
+ * @ingroup print_hooks
+ */
+function hook_print_pdf_generate($html, $meta, $paper_size = NULL, $page_orientation = NULL) {
+  $pdf = new PDF();
+  $pdf->writeHTML($html);
+
+  return $pdf->Output();
+}
+
+/**
+ * Alters the list of available PDF libraries.
+ *
+ * During the configuration of the PDF library to be used, the module needs
+ * to discover and display the available libraries. This function should use
+ * the internal _print_scan_libs() function which will scan both the module
+ * and the libraries directory in search of the unique file pattern that can
+ * be used to identify the library location.
+ *
+ * @param array $pdf_tools
+ *   An associative array using as key the format 'module|path', and as value
+ *   a string describing the discovered library, where:
+ *   - module: the machine name of the module that handles this library.
+ *   - path: the path where the library is installed, relative to DRUPAL_ROOT.
+ *     If the recommended path is used, it begins with sites/all/libraries.
+ *   As a recommendation, the value should contain in parantheses the path
+ *   where the library was found, to allow the user to distinguish between
+ *   multiple install paths of the same library version.
+ *
+ * @ingroup print_hooks
+ */
+function hook_print_pdf_available_libs_alter(&$pdf_tools) {
+  module_load_include('inc', 'print', 'includes/print');
+  $tools = _print_scan_libs('foo', '!^foo.php$!');
+
+  foreach ($tools as $tool) {
+    $pdf_tools['print_pdf_foo|' . $tool] = 'foo (' . dirname($tool) . ')';
+  }
+}
+
+/**
+ * Alters the PDF filename.
+ *
+ * Changes the value of the PDF filename variable, just before it is used to
+ * create the file. When altering the variable, do not suffix it with the
+ * '.pdf' extension, as the module will do that automatically.
+ *
+ * @param string $pdf_filename
+ *   current value of the pdf_filename variable, after processing tokens and
+ *   any transliteration steps.
+ * @param string $path
+ *   original alias/system path of the page being converted to PDF.
+ *
+ * @ingroup print_hooks
+ */
+function hook_print_pdf_filename_alter(&$pdf_filename, &$path) {
+  $pdf_filename = 'foo';
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */

+ 23 - 176
sites/all/modules/contrib/admin/print/print_pdf/print_pdf.drush.inc

@@ -5,32 +5,19 @@
  * drush integration for print_pdf module PDF libraries download.
  */
 
-/**
- * The PDF project download URL
- */
-
-// TCPDF is in sourceforge, and nicely provides a link to the latest version
-define('TCPDF_DOWNLOAD_URI', 'http://sourceforge.net/projects/tcpdf/files/latest');
-
-// URI to the the latest dompdf version.. Hardcoded version unfortunately
-define('DOMPDF_DOWNLOAD_URI', 'http://dompdf.googlecode.com/files/dompdf_0-6-0_beta3.tar.gz');
-
-// wkhtmltopdf is a binary, requiring a different download for each platform
-define('WKHTMLTOPDF_AMD64_DOWNLOAD_URI', 'http://wkhtmltopdf.googlecode.com/files/wkhtmltopdf-0.11.0_rc1-static-amd64.tar.bz2');
-define('WKHTMLTOPDF_I386_DOWNLOAD_URI', 'http://wkhtmltopdf.googlecode.com/files/wkhtmltopdf-0.11.0_rc1-static-i386.tar.bz2');
-define('WKHTMLTOPDF_WIN_DOWNLOAD_URI', 'http://wkhtmltopdf.googlecode.com/files/wkhtmltox-0.11.0_rc1-installer.exe');
-define('WKHTMLTOPDF_OSX_DOWNLOAD_URI', 'http://wkhtmltopdf.googlecode.com/files/wkhtmltopdf-OSX-0.10.0_rc2-static.tar.bz2');
-
 /**
  * Implements hook_drush_command().
  */
 function print_pdf_drush_command() {
   $items = array();
 
+  $pdf_libs = array();
+  drush_command_invoke_all_ref('drush_pdf_libs_alter', $pdf_libs);
+
   $items['print-pdf-download'] = array(
-    'description' => 'Download a PDF library.',
+    'description' => 'Download and extract a PDF library.',
     'arguments' => array(
-      'library' => dt('The PDF library to download. Either tcpdf, dompdf or wkhtmltopdf.'),
+      'library' => dt('The PDF library to download. Available choices: !libs.', array('!libs' => implode(', ', array_keys($pdf_libs)))),
     ),
     'options' => array(
       'path' => dt('A path to the download folder. If omitted Drush will use the default location (@path).', array('@path' => 'sites/all/libraries')),
@@ -43,176 +30,36 @@ function print_pdf_drush_command() {
 }
 
 /**
- * Download and extract PDF archive.
+ * Implements of drush_hook_COMMAND_validate().
  */
-function drush_print_pdf_download($library) {
-  if (isset($library)) {
-    $download_url = _drush_print_pdf_download_url($library);
-    if ($download_url) {
-      $path = drush_get_option('path');
-      if (empty($path)) {
-        $path = drush_get_context('DRUSH_DRUPAL_ROOT') . '/sites/all/libraries';
-      }
-
-      // Create the path if it does not exist.
-      if (!is_dir($path)) {
-        drush_op('mkdir', $path);
-        drush_log(dt('Directory @path was created', array('@path' => $path)), 'notice');
-      }
+function drush_print_pdf_download_validate($library = NULL) {
+  if (is_null($library)) {
+    $pdf_libs = array();
+    drush_command_invoke_all_ref('drush_pdf_libs_alter', $pdf_libs);
 
-      // Chdir to the download location.
-      $olddir = getcwd();
-      drush_op('chdir', $path);
-
-      // Warn about an existing dir
-      if (is_dir($library)) {
-        // drush_op('rmdir', $library); // Directory must be empty for the php rmdir to work..
-        drush_log(dt('An existing @library was overwritten at @path', array('@library' => $library, '@path' => $path . '/' . $library)), 'notice');
-      }
-
-      // Download the archive
-      $filename = _drush_print_pdf_download_file($download_url);
-      if ($filename) {
-        $extract_ret = _drush_print_pdf_download_extract($filename);
-        if ($extract_ret) {
-          // Remove the archive
-          drush_op('unlink', $filename);
-          drush_log(dt('@file has been downloaded and extracted in @path', array('@file' => $filename, '@path' => $path)), 'success');
-        }
-        else {
-          drush_log(dt('@file has been downloaded to @path, but extract failed. Check that you have the necessary program installed, and if necessary extract it manually.',
-                    array('@file' => $filename, '@path' => $path)), 'warning');
-        }
-      }
-      else {
-        drush_log(dt('Drush was unable to download @library to @path', array('@library' => $library, '@path' => $path)), 'error');
-      }
-
-      // Set working directory back to the previous working directory.
-      drush_op('chdir', $olddir);
-    }
-  }
-  else {
-    drush_log(dt('Please specify a PDF library. Currently supported libraries are dompdf, tcpdf and wkhtmltopdf.'), 'error');
+    drush_set_error('DRUSH_PDFDL_MISSING_ARG', dt("Usage: drush !cmd <library>\nWhere <library> is one of the following: !libs\n\nTry 'drush !cmd --help' for more information.", array('!cmd' => 'print-pdf-download', '!libs' => implode(', ', array_keys($pdf_libs)))));
   }
 }
 
 /**
- * Discover the correct URL of the package to download
- */
-function _drush_print_pdf_download_url($library) {
-  $ret = FALSE;
-
-  switch (drupal_strtolower($library)) {
-    case 'dompdf':
-      $ret = DOMPDF_DOWNLOAD_URI;
-      break;
-    case 'tcpdf':
-      $ret = TCPDF_DOWNLOAD_URI;
-      break;
-    case 'wkhtmltopdf':
-      switch (drupal_substr(php_uname('s'), 0, 3)) {
-        case 'Lin':
-          $ret = (php_uname('m') == 'x86_64') ? WKHTMLTOPDF_AMD64_DOWNLOAD_URI : WKHTMLTOPDF_I386_DOWNLOAD_URI;
-          break;
-        case 'Win':
-          $ret = WKHTMLTOPDF_WIN_DOWNLOAD_URI;
-          break;
-        case 'Dar':
-          $ret = WKHTMLTOPDF_OSX_DOWNLOAD_URI;
-          break;
-        default:
-          drush_log(dt('wkhtmltopdf is not supported in this system, please choose another library.'), 'error');
-          break;
-      }
-      break;
-    default:
-      drush_log(dt('Unknown PDF library specified, please use one of the supported PDF libraries.'), 'error');
-      break;
-  }
-
-  return $ret;
-}
-
-/**
- * Helper to download and extract the zip/tar archive.
- */
-function _drush_print_pdf_download_extract($filename) {
-  $arch_ret = FALSE;
-
-  if (drush_op('is_file', $filename)) {
-    switch (drush_op('mime_content_type', $filename)) {
-      case 1:
-        $arch_ret = TRUE;
-        break;
-      case 'application/zip':
-        // Decompress the zip archive
-        $arch_ret = drush_shell_exec('unzip -qq -o ' . $filename);
-        // ZIP archives usually get the access rights wrong
-        drush_log(dt('@filename is a Zip file. Check the access permissions of the extracted files.', array('@filename' => $filename)), 'warning');
-        break;
-      case 'application/x-gzip':
-        // Decompress the tar gz archive
-        $arch_ret = drush_shell_exec('tar xzf ' . $filename);
-        break;
-      case 'application/x-bzip2':
-        // Decompress the tar bz2 archive
-        $arch_ret = drush_shell_exec('tar xjf ' . $filename);
-        break;
-    }
-  }
-  else {
-    drush_log(dt('@filename not found.', array('@filename' => $filename)), 'error');
-  }
-
-  return $arch_ret;
-}
-
-/**
- * Download a file using wget or curl
- *
- * Adapted from a function in drush/includes/drush.inc to support 302 redirects.
- *
- * @param string $download_url
- *   The path to the file to download
+ * Download and extract PDF archive.
  *
- * @return string
- *   The filename that was downloaded, or NULL if the file could not be
- *   downloaded.
+ * @param string $library
+ *   library to download
  */
-function _drush_print_pdf_download_file($download_url) {
-  $wget_ret = drush_shell_exec("wget -nv --trust-server-names %s", $download_url);
-
-  if (!drush_get_context('DRUSH_SIMULATE')) {
-    if ($wget_ret) {
-      // Get the filename of the saved file from the output
-      $wget_out = explode('"', array_shift(drush_shell_exec_output()));
-      $filename = $wget_out[1];
-    }
-    else {
-      $tempnam = uniqid('drush_print_pdf_');
-
-      $curl_ret = drush_shell_exec("curl -s -L -o %s %s -w '%%{url_effective}'", $tempnam, $download_url);
-      if ($curl_ret) {
-        // File was donwloaded with the tempname
+function drush_print_pdf_download($library) {
+  $pdf_libs = array();
+  drush_command_invoke_all_ref('drush_pdf_libs_alter', $pdf_libs);
 
-        // Find the effective name
-        $filename = explode('/', array_shift(drush_shell_exec_output()));
-        $filename = array_pop($filename);
+  if (isset($library) && isset($pdf_libs[drupal_strtolower($library)])) {
+    $func = $pdf_libs[drupal_strtolower($library)]['callback'];
 
-        // Rename file from tempname to effective name
-        if (!drush_op('rename', $tempnam, './' . $filename)) {
-          $filename = $tempnam;
-        }
-      }
-      else {
-        $filename = FALSE;
-      }
+    $download_url = $func();
+    if ($download_url) {
+      _print_drush_download_lib($library, $download_url);
     }
   }
   else {
-    $filename = basename($download_url);
+    drush_log(dt('Please specify a PDF library. Available choices: !libs.', array('!libs' => implode(', ', array_keys($pdf_libs)))), 'error');
   }
-
-  return $filename;
 }

+ 5 - 10
sites/all/modules/contrib/admin/print/print_pdf/print_pdf.info

@@ -1,18 +1,13 @@
 name = "PDF version"
-description = "Adds the capability to export pages as PDF."
-core=7.x
+description = "Adds the capability to export pages as PDF. Requires a PDF library and the respective handler module."
+core = 7.x
 package = "Printer, email and PDF versions"
 dependencies[] = print
-files[] = print_pdf.module
-files[] = print_pdf.admin.inc
-files[] = print_pdf.pages.inc
-files[] = print_pdf.install
-files[] = print_pdf.views.inc
 configure = admin/config/user-interface/print/pdf
 
-; Information added by drupal.org packaging script on 2012-09-04
-version = "7.x-1.2"
+; Information added by Drupal.org packaging script on 2014-04-02
+version = "7.x-2.0"
 core = "7.x"
 project = "print"
-datestamp = "1346768900"
+datestamp = "1396426766"
 

+ 106 - 22
sites/all/modules/contrib/admin/print/print_pdf/print_pdf.install

@@ -27,30 +27,28 @@ function print_pdf_enable() {
  * Implements hook_uninstall().
  */
 function print_pdf_uninstall() {
-  variable_del('print_pdf_settings');
-  variable_del('print_pdf_show_link');
-  variable_del('print_pdf_link_pos');
-  variable_del('print_pdf_link_teaser');
-  variable_del('print_pdf_node_link_visibility');
-  variable_del('print_pdf_node_link_pages');
-  variable_del('print_pdf_link_class');
-  variable_del('print_pdf_sys_link_visibility');
-  variable_del('print_pdf_sys_link_pages');
-  variable_del('print_pdf_book_link');
-  variable_del('print_pdf_pdf_tool');
+  variable_del('print_pdf_autoconfig');
+  variable_del('print_pdf_cache_enabled');
+  variable_del('print_pdf_cache_lifetime');
   variable_del('print_pdf_content_disposition');
-  variable_del('print_pdf_paper_size');
-  variable_del('print_pdf_page_orientation');
+  variable_del('print_pdf_display_sys_urllist');
+  variable_del('print_pdf_filename');
   variable_del('print_pdf_images_via_file');
-  variable_del('print_pdf_font_family');
-  variable_del('print_pdf_font_size');
   variable_del('print_pdf_link_text');
+  variable_del('print_pdf_link_text_enabled');
+  variable_del('print_pdf_page_orientation');
+  variable_del('print_pdf_paper_size');
+  variable_del('print_pdf_pdf_tool');
+
+  variable_del('print_pdf_book_link');
+  variable_del('print_pdf_link_class');
+  variable_del('print_pdf_link_pos');
+  variable_del('print_pdf_link_teaser');
   variable_del('print_pdf_link_use_alias');
-  variable_del('print_pdf_filename');
-  variable_del('print_pdf_autoconfig');
-  variable_del('print_pdf_dompdf_unicode');
-  variable_del('print_pdf_wkhtmltopdf_options');
-  variable_del('print_pdf_display_sys_urllist');
+  variable_del('print_pdf_show_link');
+  variable_del('print_pdf_sys_link_pages');
+  variable_del('print_pdf_sys_link_visibility');
+
   $settings = db_query("SELECT name FROM {variable} WHERE name LIKE 'print\_pdf\_display\_%'");
   foreach ($settings as $variable) {
     variable_del($variable->name);
@@ -94,6 +92,17 @@ function print_pdf_schema() {
         'size' => 'tiny',
         'description' => 'Show Printer-friendly URLs list',
       ),
+      'size' => array(
+        'type' => 'varchar',
+        'length' => 9,
+        'description' => 'Paper size',
+      ),
+      'orientation' => array(
+        'type' => 'varchar',
+        'length' => 9,
+        'description' => 'Page orientation',
+      ),
+
     ),
     'primary key' => array('nid'),
   );
@@ -103,7 +112,7 @@ function print_pdf_schema() {
     'fields' => array(
       'path' => array(
         'type' => 'varchar',
-        'length' => 128,
+        'length' => 255,
         'not null' => TRUE,
         'description' => 'Page path',
       ),
@@ -146,12 +155,87 @@ function print_pdf_update_7000(&$sandbox) {
   }
 }
 
+/**
+ * Delete old variables
+ */
+function print_pdf_update_7200(&$sandbox) {
+  variable_del('print_pdf_settings');
+
+  variable_del('print_pdf_node_link_pages');
+  variable_del('print_pdf_node_link_visibility');
+}
+
+/**
+ * Update pdf_tool variable to new module|path format
+ */
+function print_pdf_update_7201(&$sandbox) {
+  $tool =  explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
+
+  if (count($tool) == 1) {
+    // Not an array yet, update variable to new format
+    if (preg_match('!dompdf_config.inc.php$!', $tool[0])) {
+      $tool[0] = 'print_pdf_dompdf|' . $tool[0];
+    }
+    elseif (preg_match('!tcpdf.php$!', $tool[0])) {
+      $tool[0] = 'print_pdf_tcpdf|' . $tool[0];
+    }
+    elseif (preg_match('!wkhtmltopdf!', $tool[0])) {
+      $tool[0] = 'print_pdf_wkhtmltopdf|' . $tool[0];
+    }
+    else {
+      $tool[0] = PRINT_PDF_PDF_TOOL_DEFAULT;
+    }
+
+    variable_set('print_pdf_pdf_tool', $tool[0]);
+  }
+}
+
 /**
  * Enable block and help area links
  */
-function print_pdf_update_7101(&$sandbox) {
+function print_pdf_update_7202(&$sandbox) {
   $link_pos = variable_get('print_pdf_link_pos', drupal_json_decode('{ "link": "link", "block": "block", "help": "help" }'));
   $link_pos['block'] = 'block';
   $link_pos['help'] = 'help';
   variable_set('print_pdf_link_pos', $link_pos);
 }
+
+/**
+ * Add Size and Orientation fields for per content type Size and Orientation
+ */
+function print_pdf_update_7203(&$sandbox) {
+  $spec = array(
+    'type' => 'varchar',
+    'length' => 9,
+    'description' => 'Paper size',
+  );
+  db_add_field('print_pdf_node_conf', 'size', $spec);
+  $spec = array(
+    'type' => 'varchar',
+    'length' => 9,
+    'description' => 'Page orientation',
+  );
+  db_add_field('print_pdf_node_conf', 'orientation', $spec);
+}
+
+/**
+ * Enable the PDF generation sub-module being used
+ */
+function print_pdf_update_7204(&$sandbox) {
+  // Since update_7201 already has stored the correct module in the array, use that
+  $tool =  explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
+
+  if (count($tool) == 2) {
+    module_enable(array($tool[0]), FALSE);
+  }
+}
+
+/**
+ * Increase size of the path field in the print_pdf_page_counter table
+ */
+function print_pdf_update_7205(&$sandbox) {
+  db_drop_primary_key('print_pdf_page_counter');
+  db_change_field('print_pdf_page_counter', 'path', 'path',
+    array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'description' => 'Page path'),
+    array('primary key' => array('path')));
+}

+ 349 - 479
sites/all/modules/contrib/admin/print/print_pdf/print_pdf.module

@@ -7,81 +7,46 @@
  * @ingroup print
  */
 
-define('PRINTPDF_PATH', 'printpdf');
-
-// Defined in print.module
-// define('PRINT_PDF_FORMAT', 'pdf');
-
-define('PRINT_PDF_LIB_PATH', 'sites/all/libraries');
-
-define('PRINT_PDF_LINK_POS_DEFAULT', '{ "link": "link", "block": "block", "help": "help" }');
-define('PRINT_PDF_LINK_TEASER_DEFAULT', 0);
-define('PRINT_PDF_SHOW_LINK_DEFAULT', 1);
-define('PRINT_PDF_NODE_LINK_VISIBILITY_DEFAULT', 0);
-define('PRINT_PDF_NODE_LINK_PAGES_DEFAULT', '');
-define('PRINT_PDF_LINK_CLASS_DEFAULT', 'print-pdf');
-define('PRINT_PDF_SYS_LINK_VISIBILITY_DEFAULT', 1);
-define('PRINT_PDF_SYS_LINK_PAGES_DEFAULT', '');
-define('PRINT_PDF_LINK_USE_ALIAS_DEFAULT', 0);
-define('PRINT_PDF_BOOK_LINK_DEFAULT', 1);
 define('PRINT_PDF_PDF_TOOL_DEFAULT', 0);
 define('PRINT_PDF_CONTENT_DISPOSITION_DEFAULT', 2);
 define('PRINT_PDF_PAPER_SIZE_DEFAULT', 'A4');
 define('PRINT_PDF_PAGE_ORIENTATION_DEFAULT', 'portrait');
 define('PRINT_PDF_IMAGES_VIA_FILE_DEFAULT', 0);
 define('PRINT_PDF_AUTOCONFIG_DEFAULT', 1);
-define('PRINT_PDF_FONT_FAMILY_DEFAULT', 'dejavusans');
-define('PRINT_PDF_FONT_SIZE_DEFAULT', 10);
-define('PRINT_PDF_FONT_SUBSETTING_DEFAULT', FALSE);
 define('PRINT_PDF_FILENAME_DEFAULT', '[site:name] - [node:title] - [node:changed:custom:Y-m-d]');
-define('PRINT_PDF_DOMPDF_UNICODE_DEFAULT', 0);
-define('PRINT_PDF_WKHTMLTOPDF_OPTIONS', "--footer-font-size 7 --footer-right '[page]'");
-define('PRINT_PDF_DOMPDF_CACHE_DIR_DEFAULT', 'print_pdf/dompdf');
-define('PRINT_PDF_TCPDF_CACHE_DIR_DEFAULT', 'print_pdf/tcpdf');
+define('PRINT_PDF_CACHE_ENABLED_DEFAULT', 0);
+define('PRINT_PDF_CACHE_LIFETIME_DEFAULT', 86400); // 1 day
 
 /**
- * Implements hook_permission().
+ * Implements hook_print_link().
  */
-function print_pdf_permission() {
+function print_pdf_print_link() {
   return array(
-    'access PDF version' => array(
-      'title' => t('Access the PDF version'),
-      'description' => t('View the PDF versions and the links to them in the original pages.'),
-    ),
+    'format' => 'pdf',
+    'text' => t('PDF version'),
+    'description' => t('Display a PDF version of this page.'),
+    'path' => 'printpdf',
+    'class' => 'print-pdf',
+    'icon' => 'pdf_icon.png',
+    'module' => 'print_pdf',
   );
 }
 
 /**
- * Implements hook_theme().
+ * Implements hook_print_new_window_alter().
+ */
+function print_pdf_print_new_window_alter(&$new_window, $format) {
+  $new_window = (variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT) == 1);
+}
+
+/**
+ * Implements hook_permission().
  */
-function print_pdf_theme() {
+function print_pdf_permission() {
   return array(
-    'print_pdf_format_link' => array(
-      'variables' => array(),
-    ),
-    'print_pdf_dompdf_footer' => array(
-      'variables' => array('html' => ''),
-      'file' => 'print_pdf.pages.inc',
-    ),
-    'print_pdf_tcpdf_header' => array(
-      'variables' => array('pdf' => NULL, 'html' => '', 'font' => array()),
-      'file' => 'print_pdf.pages.inc',
-    ),
-    'print_pdf_tcpdf_page' => array(
-      'variables' => array('pdf' => NULL),
-      'file' => 'print_pdf.pages.inc',
-    ),
-    'print_pdf_tcpdf_content' => array(
-      'variables' => array('pdf' => NULL, 'html' => '', 'font' => array()),
-      'file' => 'print_pdf.pages.inc',
-    ),
-    'print_pdf_tcpdf_footer' => array(
-      'variables' => array('pdf' => NULL, 'html' => '', 'font' => array()),
-      'file' => 'print_pdf.pages.inc',
-    ),
-    'print_pdf_tcpdf_footer2' => array(
-      'variables' => array('pdf' => NULL),
-      'file' => 'print_pdf.pages.inc',
+    'access PDF version' => array(
+      'title' => t('Access the PDF version'),
+      'description' => t('View the PDF versions and the links to them in the original pages.'),
     ),
   );
 }
@@ -91,41 +56,60 @@ function print_pdf_theme() {
  */
 function print_pdf_init() {
   if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
-    $pdf_dirs = array();
     $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
-
-    if (basename($print_pdf_pdf_tool) == 'dompdf_config.inc.php') {
-      $pdf_dirs[] = PRINT_PDF_DOMPDF_CACHE_DIR_DEFAULT . '/fonts';
-    }
-    elseif (basename($print_pdf_pdf_tool) == 'tcpdf.php') {
-      foreach (array('cache', 'images') as $dir) {
-        $pdf_dirs[] = PRINT_PDF_TCPDF_CACHE_DIR_DEFAULT . '/' . $dir;
-      }
+    $tool = explode('|', $print_pdf_pdf_tool);
+    $function = $tool[0] . '_pdf_tool_info';
+    if (function_exists($function)) {
+      $info = $function();
     }
 
-    if (!empty($pdf_dirs)) {
-      foreach ($pdf_dirs as $pdf_dir) {
-        $directory = 'public://' . $pdf_dir;
-        file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
+    if (isset($info['public_dirs'])) {
+      foreach ($info['public_dirs'] as $dir) {
+        $directory = 'public://print_pdf/' . $tool[0] . '/' . $dir;
+        $wrapper = file_stream_wrapper_get_instance_by_uri($directory);
+        $real_directory_path = $wrapper->getDirectoryPath() . "/" . file_uri_target($directory);
+        $result = file_prepare_directory($real_directory_path, FILE_CREATE_DIRECTORY);
+        if (!$result) {
+          watchdog('print_pdf', 'Failed to create directory "%dir" for %tool.', array('%dir' => $directory, '%tool' => $tool[0]), WATCHDOG_CRITICAL);
+        }
       }
     }
   }
+  if (variable_get('print_pdf_cache_enabled', PRINT_PDF_CACHE_ENABLED_DEFAULT)) {
+    $directory = print_pdf_cache_dir();
+    $wrapper = file_stream_wrapper_get_instance_by_uri($directory);
+    $real_directory_path = $wrapper->getDirectoryPath() . "/" . file_uri_target($directory);
+    $result = file_prepare_directory($real_directory_path, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY);
+    if (!$result) {
+      watchdog('print_pdf', 'Failed to create directory "%dir" for print_pdf cache.', array('%dir' => $directory), WATCHDOG_CRITICAL);
+    }
+  }
+}
+
+/**
+ * Implements hook_flush_caches().
+ */
+function print_pdf_flush_caches() {
+  print_pdf_cache_delete();
+
+  return array();
 }
 
 /**
  * Implements hook_menu().
  */
 function print_pdf_menu() {
+  $link = print_pdf_print_link();
   $items = array();
 
-  $items[PRINTPDF_PATH] = array(
+  $items[$link['path']] = array(
     'title' => 'Printer-friendly PDF',
     'page callback' => 'print_pdf_controller',
     'access arguments' => array('access PDF version'),
     'type' => MENU_CALLBACK,
     'file' => 'print_pdf.pages.inc',
   );
-  $items[PRINTPDF_PATH . '/' . PRINTPDF_PATH] = array(
+  $items[$link['path'] . '/' . $link['path']] = array(
     'access callback' => FALSE,
   );
   $items['admin/config/user-interface/print/pdf'] = array(
@@ -140,51 +124,57 @@ function print_pdf_menu() {
   );
   $items['admin/config/user-interface/print/pdf/options'] = array(
     'title' => 'Options',
-    'weight' => 1,
+    'weight' => -1,
     'type' => MENU_DEFAULT_LOCAL_TASK,
   );
-  $items['admin/config/user-interface/print/pdf/strings'] = array(
-    'title' => 'Text strings',
-    'description' => 'Override the user-facing strings used in the PDF version.',
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('print_pdf_strings_settings'),
-    'access arguments'  => array('administer print'),
-    'weight' => 2,
-    'type' => MENU_LOCAL_TASK,
-    'file' => 'print_pdf.admin.inc',
-  );
 
   return $items;
 }
 
+/**
+ * Implements hook_variable_info().
+ */
+function print_pdf_variable_info($options) {
+  $link = print_pdf_print_link();
+
+  $variable['print_pdf_link_text'] = array(
+    'title' => t('PDF version'),
+    'description' => t('Text used in the link to the PDF version.'),
+    'type' => 'string',
+    'default' => t($link['text']),
+  );
+
+  return $variable;
+}
+
 /**
  * Implements hook_block_info().
  */
 function print_pdf_block_info() {
-      $block['print_pdf-top']['info'] = t('Most PDFd');
-      $block['print_pdf-top']['cache'] = DRUPAL_CACHE_GLOBAL;
-      return $block;
+  $block['print_pdf-top']['info'] = t('Most PDFd');
+  $block['print_pdf-top']['cache'] = DRUPAL_CACHE_GLOBAL;
+  return $block;
 }
 
 /**
  * Implements hook_block_view().
  */
 function print_pdf_block_view($delta = 0) {
-      switch ($delta) {
-      case 'print_pdf-top':
-        $block['subject'] = t('Most PDFd');
-        $result = db_query_range("SELECT path FROM {print_pdf_page_counter} LEFT JOIN {node} n ON path = CONCAT('node/', n.nid) WHERE status <> 0 OR status IS NULL ORDER BY totalcount DESC", 0, 3)
-                    ->fetchAll();
-        if (count($result)) {
-          $block['content'] = '<div class="item-list"><ul>';
-          foreach ($result as $obj) {
-            $block['content'] .= '<li>' . l(_print_get_title($obj->path), $obj->path) . '</li>';
-          }
-          $block['content'] .= '</ul></div>';
+  switch ($delta) {
+    case 'print_pdf-top':
+      $block['subject'] = t('Most PDFd');
+      $result = db_query_range("SELECT path FROM {print_pdf_page_counter} LEFT JOIN {node} n ON path = CONCAT('node/', n.nid) WHERE status <> 0 OR status IS NULL ORDER BY totalcount DESC", 0, 3)
+                  ->fetchAll();
+      if (count($result)) {
+        $items = array();
+        foreach ($result as $obj) {
+          $items[] = l(_print_get_title($obj->path), $obj->path);
         }
-        break;
+        $block['content'] = theme('item_list', array('items' => $items, 'type' => 'ul'));
       }
-      return $block;
+      break;
+  }
+  return $block;
 }
 
 /**
@@ -206,84 +196,69 @@ function print_pdf_requirements($phase) {
         );
       }
       else {
-        if (!is_file($print_pdf_pdf_tool) || !is_readable($print_pdf_pdf_tool)) {
+        // Tool is defined, get some data from it's handler module
+        $tool = explode('|', $print_pdf_pdf_tool);
+        $function = $tool[0] . '_pdf_tool_info';
+        if (function_exists($function)) {
+          $info = $function();
+        }
+
+        // Is the file there?
+        if (!is_file($tool[1]) || !is_readable($tool[1])) {
           $requirements['print_pdf_tool'] = array(
             'title' => $t('Printer, email and PDF versions - PDF generation library'),
             'value' => $t('File not found'),
-            'description' => $t('The currently selected PDF generation library (%file) is no longer accessible.', array('%file' => $print_pdf_pdf_tool)),
+            'description' => $t('The currently selected PDF generation library (%file) is no longer accessible.', array('%file' => $tool[1])),
             'severity' => REQUIREMENT_ERROR,
           );
         }
-        elseif (basename($print_pdf_pdf_tool) == 'dompdf_config.inc.php') {
-          if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
-            $directory = 'public://' . PRINT_PDF_DOMPDF_CACHE_DIR_DEFAULT . '/fonts';
-            if (!is_dir($directory) || !is_writable($directory)) {
-              $requirements['print_pdf_tool'] = array(
-                'title' => $t('DOMPDF font cache directory'),
-                'value' => $t('Non-writable permissions'),
-                'description' => $t('You must change the %fontdir permissions to be writable, as dompdf requires write-access to that directory.', array('%fontdir' => $directory)),
+        else {
+          // Get the version number
+          $function = $tool[0] . '_pdf_tool_version';
+          if (function_exists($function)) {
+            $version = $function($tool[1]);
+
+            if (isset($info['min_version']) && version_compare($version, $info['min_version'], '<')) {
+              $requirements['print_pdf_tool_version'] = array(
+                'title' => $t('Printer, email and PDF versions - PDF generation library'),
+                'value' => $t('Unsupported %lib version', array('%lib' => $info['name'])),
+                'description' => $t('The currently selected version of %lib (@version) is not supported. Please update to a !url.',
+                                    array('%lib' => $info['name'], '@version' => $version, '!url' => l($t('newer version'), $info['url']))),
                 'severity' => REQUIREMENT_ERROR,
               );
             }
+            else {
+              $requirements['print_pdf_tool_version'] = array(
+                'title' => $t('Printer, email and PDF versions - PDF generation library'),
+                'value' => $info['name'] . ' ' . $version,
+              );
+            }
           }
         }
-        elseif (basename($print_pdf_pdf_tool) == 'tcpdf.php') {
-          $version = _print_pdf_tcpdf_version();
-
-          if (version_compare($version, '5.9.001', '<')) {
-            $requirements['print_pdf_tool'] = array(
-              'title' => $t('Printer, email and PDF versions - PDF generation library'),
-              'value' => $t('Unsupported TCPDF version'),
-              'description' => $t('The currently selected version of TCPDF (@version) is not supported. Please update to a !url.', array('@version' => $version, '!url' => l($t('newer version'), 'http://sourceforge.net/projects/tcpdf/files/latest'))),
-              'severity' => REQUIREMENT_ERROR,
-            );
-          }
-          else {
-            $requirements['print_pdf_tool'] = array(
-              'title' => $t('Printer, email and PDF versions - PDF generation library'),
-              'value' => $t('TCPDF') . ' ' . $version,
-            );
-          }
 
-          if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
-            foreach (array('cache', 'images') as $dir) {
-              $directory = 'public://' . PRINT_PDF_TCPDF_CACHE_DIR_DEFAULT . '/' . $dir;
-              if (!is_dir($directory) || !is_writable($directory)) {
-                $requirements['print_pdf_tool_' . $dir] = array(
-                  'title' => $t('TCPDF directory'),
-                  'value' => $t('Non-writable permissions'),
-                  'description' => $t('You must change the %fontdir permissions to be writable, as TCPDF requires write-access to that directory.', array('%fontdir' => $directory)),
-                  'severity' => REQUIREMENT_ERROR,
-                );
-              }
+        // If auto-config is on, check for write access to the appropriate dirs
+        if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
+          $directories = array();
+          if (isset($info['public_dirs'])) {
+            foreach ($info['public_dirs'] as $dir) {
+              $directories[] = 'public://print_pdf/' . $tool[0] . '/' . $dir;
             }
           }
-        }
-        elseif (drupal_substr(basename($print_pdf_pdf_tool, '.exe'), 0, 11) == 'wkhtmltopdf') {
-          if (function_exists('is_executable') && !is_executable($print_pdf_pdf_tool)) {
-            $requirements['print_pdf_tool'] = array(
-              'title' => $t('wkhtmltopdf library'),
-              'value' => $t('Non-executable permissions'),
-              'description' => $t('You must modify the permissions of the wkhtmltopdf file (%file) to make it executable.', array('%file' => $print_pdf_pdf_tool)),
-              'severity' => REQUIREMENT_ERROR,
-            );
+          if (isset($info['tool_dirs'])) {
+            foreach ($info['tool_dirs'] as $dir) {
+              $directories[] = dirname($tool[1]) . '/' . $dir;
+            }
           }
-          else {
-            $version = _print_pdf_wkhtmltopdf_version();
-            if (version_compare($version, '0.9.6', '<')) {
-              $requirements['print_pdf_tool'] = array(
-                'title' => $t('Printer, email and PDF versions - PDF generation library'),
-                'value' => $t('Unsupported wkhtmltopdf version'),
-                'description' => $t('The currently selected version of wkhtmltopdf (@version) is not supported. Please update to a !url.', array('@version' => $version, '!url' => l($t('newer version'), 'http://code.google.com/p/wkhtmltopdf/'))),
+
+          foreach ($directories as $dir) {
+            if (!is_dir($dir) || !is_writable($dir)) {
+              $requirements['print_pdf_tool_' . $dir] = array(
+                'title' => $t('%lib directory', array('%lib' => $info['name'])),
+                'value' => $t('Non-writable permissions'),
+                'description' => $t('You must change the %libdir permissions to be writable, as %lib requires write-access to that directory.', array('%lib' => $info['name'], '%libdir' => $dir)),
                 'severity' => REQUIREMENT_ERROR,
               );
             }
-            else {
-              $requirements['print_pdf_tool'] = array(
-                'title' => $t('Printer, email and PDF versions - PDF generation library'),
-                'value' => $t('wkhtmltopdf') . ' ' . $version,
-              );
-            }
           }
         }
       }
@@ -292,87 +267,6 @@ function print_pdf_requirements($phase) {
   return $requirements;
 }
 
-/**
- * Implements hook_node_view().
- */
-function print_pdf_node_view($node, $view_mode) {
-  $print_pdf_link_pos = variable_get('print_pdf_link_pos', drupal_json_decode(PRINT_PDF_LINK_POS_DEFAULT));
-  $print_pdf_link_use_alias = variable_get('print_pdf_link_use_alias', PRINT_PDF_LINK_USE_ALIAS_DEFAULT);
-
-  foreach (array('node', 'comment') as $type) {
-    $allowed_type = print_pdf_link_allowed(array('type' => $type, 'node' => $node, 'view_mode' => $view_mode));
-    if (($allowed_type) && !empty($print_pdf_link_pos['link'])) {
-      drupal_add_css(drupal_get_path('module', 'print') . '/css/printlinks.css');
-      $links = array();
-      $format = theme('print_pdf_format_link');
-
-      // Show book link
-      if ($allowed_type === PRINT_ALLOW_BOOK_LINK) {
-        $links['book_pdf'] = array(
-          'href' => PRINTPDF_PATH . '/book/export/html/' . $node->nid,
-          'title' => $format['text'],
-          'attributes' => $format['attributes'],
-          'html' => $format['html'],
-        );
-      }
-      elseif ($allowed_type === PRINT_ALLOW_NORMAL_LINK) {
-        $path = (($print_pdf_link_use_alias) && ($alias = drupal_lookup_path('alias', 'node/' . $node->nid))) ? $alias : $node->nid;
-
-        $links['print_pdf'] = array(
-          'href' => PRINTPDF_PATH . '/' . $path,
-          'title' => $format['text'],
-          'attributes' => $format['attributes'],
-          'html' => $format['html'],
-          'query' => print_query_string_encode($_GET, array('q')),
-        );
-      }
-
-      $link_content = array(
-        '#theme' => 'links',
-        '#links' => $links,
-        '#attributes' => array('class' => array('links', 'inline')),
-      );
-
-      if ($type == 'node') {
-        
-        $node->content['links']['print_pdf'] = $link_content;
-      }
-      elseif (($type == 'comment') && isset($node->content['comments']['comments'])) {
-        foreach ($node->content['comments']['comments'] as $cid => $comment) {
-          if (is_numeric($cid)) {
-            $link_content['#links']['print_pdf']['query']['comment'] = $cid;
-            $node->content['comments']['comments'][$cid]['links']['print_pdf'] = $link_content;
-          }
-        }
-      }
-    }
-  }
-
-  // Insert content corner links
-  if ((!empty($print_pdf_link_pos['corner'])) && ($view_mode == 'full')) {
-    $node->content['print_links']['#markup'] .= print_pdf_insert_link(NULL, $node);
-  }
-}
-
-/**
- * Implements hook_help().
- */
-function print_pdf_help($path, $arg) {
-  $print_pdf_link_pos = variable_get('print_pdf_link_pos', drupal_json_decode(PRINT_PDF_LINK_POS_DEFAULT));
-  if (($path !== 'node/%') && !(empty($print_pdf_link_pos['help']))) {
-    static $output = FALSE;
-
-    if ($output === FALSE) {
-      $output = TRUE;
-
-      $link = print_pdf_insert_link();
-      if ($link) {
-        return "<span class='print-syslink'>$link</span>";
-      }
-    }
-  }
-}
-
 /**
  * Implements hook_node_load().
  */
@@ -382,12 +276,16 @@ function print_pdf_node_load($nodes, $types) {
     $ids[] = $node->nid;
   }
 
-  $result = db_query('SELECT nid, link, comments, url_list FROM {print_pdf_node_conf} WHERE nid IN (:nids)', array(':nids' => $ids))->fetchAllAssoc('nid');
+  $link = print_pdf_print_link();
+
+  $size = 'print_' . $link['format'] . '_size';
+  $orientation = 'print_' . $link['format'] . '_orientation';
+
+  $result = db_query('SELECT nid, size, orientation FROM {print_pdf_node_conf} WHERE nid IN (:nids)', array(':nids' => $ids))->fetchAllAssoc('nid');
 
   foreach ($nodes as $node) {
-    $node->print_pdf_display = isset($result[$node->nid]) ? intval($result[$node->nid]->link) : variable_get('print_pdf_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-    $node->print_pdf_display_comment = isset($result[$node->nid]) ? intval($result[$node->nid]->comments) : variable_get('print_pdf_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-    $node->print_pdf_display_urllist = isset($result[$node->nid]) ? intval($result[$node->nid]->url_list) : variable_get('print_pdf_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
+    $node->{$size} = (isset($result[$node->nid]) && !empty($result[$node->nid]->size)) ? $result[$node->nid]->size : variable_get($size . '_' . $node->type);
+    $node->{$orientation} = (isset($result[$node->nid]) && !empty($result[$node->nid]->orientation)) ? $result[$node->nid]->orientation : variable_get($orientation . '_' . $node->type);
   }
 }
 
@@ -395,13 +293,7 @@ function print_pdf_node_load($nodes, $types) {
  * Implements hook_node_insert().
  */
 function print_pdf_node_insert($node) {
-  if (user_access('administer print') || user_access('node-specific print configuration')) {
-    if (!isset($node->print_pdf_display)) $node->print_pdf_display = variable_get('print_pdf_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-    if (!isset($node->print_pdf_display_comment)) $node->print_pdf_display_comment = variable_get('print_pdf_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-    if (!isset($node->print_pdf_display_urllist)) $node->print_pdf_display_urllist = variable_get('print_pdf_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
-
-    _print_pdf_node_conf_modify($node->nid, $node->print_pdf_display, $node->print_pdf_display_comment, $node->print_pdf_display_urllist);
-  }
+  return print_pdf_node_update($node);
 }
 
 /**
@@ -409,169 +301,98 @@ function print_pdf_node_insert($node) {
  */
 function print_pdf_node_update($node) {
   if (user_access('administer print') || user_access('node-specific print configuration')) {
-    if (!isset($node->print_pdf_display)) $node->print_pdf_display = variable_get('print_pdf_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-    if (!isset($node->print_pdf_display_comment)) $node->print_pdf_display_comment = variable_get('print_pdf_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-    if (!isset($node->print_pdf_display_urllist)) $node->print_pdf_display_urllist = variable_get('print_pdf_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
+    $link = print_pdf_print_link();
+
+    $size = 'print_' . $link['format'] . '_size';
+    $orientation = 'print_' . $link['format'] . '_orientation';
 
-    _print_pdf_node_conf_modify($node->nid, $node->print_pdf_display, $node->print_pdf_display_comment, $node->print_pdf_display_urllist);
+    if (!isset($node->{$size})) $node->{$size} = variable_get($size . '_' . $node->type);
+    if (!isset($node->{$orientation})) $node->{$orientation} = variable_get($orientation . '_' . $node->type);
+
+    db_merge('print_pdf_node_conf')
+      ->key(array('nid' => $node->nid))
+      ->fields(array(
+        'size' => $node->{$size},
+        'orientation' => $node->{$orientation},
+      ))
+      ->execute();
   }
+
+  print_pdf_cache_delete($node->nid);
 }
 
 /**
  * Implements hook_node_delete().
  */
 function print_pdf_node_delete($node) {
-  db_delete('print_pdf_node_conf')
-    ->condition('nid', $node->nid)
-    ->execute();
   db_delete('print_pdf_page_counter')
     ->condition('path', 'node/' . $node->nid)
     ->execute();
+
+  print_pdf_cache_delete($node->nid);
 }
 
 /**
  * Implements hook_form_alter().
  */
 function print_pdf_form_alter(&$form, &$form_state, $form_id) {
-  // Add the node-type settings option to activate the PDF version link
+  // Add the node-type settings option to activate the printer-friendly version link
   if ((user_access('administer print') || user_access('node-specific print configuration')) &&
       (($form_id == 'node_type_form') || !empty($form['#node_edit_form']))) {
-    $form['print']['pdf_label'] = array(
-      '#type' => 'markup',
-      '#markup' => '<p><strong>' . t('PDF version') . '</strong></p>',
-    );
+    $link = print_pdf_print_link();
 
-    $form['print']['print_pdf_display'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show link'),
-    );
-    $form['print']['print_pdf_display_comment'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show link in individual comments'),
+    $size = 'print_' . $link['format'] . '_size';
+    $orientation = 'print_' . $link['format'] . '_orientation';
+
+    $form['print']['print_' . $link['format']][$size] = array(
+      '#type' => 'select',
+      '#title' => t('Paper size'),
+      '#options' => _print_pdf_paper_sizes(TRUE),
+      '#description' => t('Choose the paper size of the generated PDF.'),
     );
-    $form['print']['print_pdf_display_urllist'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Show Printer-friendly URLs list'),
+
+    $form['print']['print_' . $link['format']][$orientation] = array(
+      '#type' => 'select',
+      '#title' => t('Page orientation'),
+      '#options' => array('' => 'Unchanged', 'portrait' => t('Portrait'), 'landscape' => t('Landscape')),
+      '#description' => t('Choose the page orientation of the generated PDF.'),
     );
 
     if ($form_id == 'node_type_form') {
-      $form['print']['print_pdf_display']['#default_value'] = variable_get('print_pdf_display_' . $form['#node_type']->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-      $form['print']['print_pdf_display_comment']['#default_value'] = variable_get('print_pdf_display_comment_' . $form['#node_type']->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-      $form['print']['print_pdf_display_urllist']['#default_value'] = variable_get('print_pdf_display_urllist_' . $form['#node_type']->type, PRINT_TYPE_URLLIST_DEFAULT);
+      $form['print']['print_' . $link['format']][$size]['#default_value'] = variable_get($size . '_' . $form['#node_type']->type);
+      $form['print']['print_' . $link['format']][$orientation]['#default_value'] = variable_get($orientation . '_' . $form['#node_type']->type);
     }
     else {
       $node = $form['#node'];
-      $form['print']['print_pdf_display']['#default_value'] = isset($node->print_pdf_display) ? $node->print_pdf_display : variable_get('print_pdf_display_' . $node->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
-      $form['print']['print_pdf_display_comment']['#default_value'] = isset($node->print_pdf_display_comment) ? $node->print_pdf_display_comment : variable_get('print_pdf_display_comment_' . $node->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-      $form['print']['print_pdf_display_urllist']['#default_value'] = isset($node->print_pdf_display_urllist) ? $node->print_pdf_display_urllist : variable_get('print_pdf_display_urllist_' . $node->type, PRINT_TYPE_URLLIST_DEFAULT);
+      $form['print']['print_' . $link['format']][$size]['#default_value'] = isset($node->{$size}) ? $node->{$size} : variable_get($size . '_' . $node->type);
+      $form['print']['print_' . $link['format']][$orientation]['#default_value'] = isset($node->{$orientation}) ? $node->{$orientation} : variable_get($orientation . '_' . $node->type);
     }
   }
 }
 
-/**
- * Update the print_pdf_node_conf table to reflect the given attributes
- *
- * If updating to the default values, delete the record.
- *
- * @param $nid
- *   value of the nid field (primary key)
- * @param $link
- *   value of the link field (0 or 1)
- * @param $comments
- *   value of the comments field (0 or 1)
- * @param $url_list
- *   value of the url_list field (0 or 1)
- */
-function _print_pdf_node_conf_modify($nid, $link, $comments, $url_list) {
-    db_merge('print_pdf_node_conf')
-      ->key(array('nid' => $nid))
-      ->fields(array(
-        'link' => $link,
-        'comments' => $comments,
-        'url_list' => $url_list,
-      ))
-      ->execute();
-}
-
-/**
- * Format the PDF version link
- *
- * @return
- *   array of formatted attributes
- * @ingroup themeable
- */
-function theme_print_pdf_format_link() {
-  $print_pdf_link_class  = variable_get('print_pdf_link_class', PRINT_PDF_LINK_CLASS_DEFAULT);
-  $print_pdf_content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
-  $print_pdf_show_link = variable_get('print_pdf_show_link', PRINT_PDF_SHOW_LINK_DEFAULT);
-  $print_pdf_link_text = filter_xss(variable_get('print_pdf_link_text', t('PDF version')));
-
-  $img = drupal_get_path('module', 'print') . '/icons/pdf_icon.gif';
-  $title = t('Display a PDF version of this page.');
-  $class = strip_tags($print_pdf_link_class);
-  $new_window = ($print_pdf_content_disposition == 1);
-  $format = _print_format_link_aux($print_pdf_show_link, $print_pdf_link_text, $img);
-
-  return array('text' => $format['text'],
-               'html' => $format['html'],
-               'attributes' => print_fill_attributes($title, $class, $new_window),
-              );
-}
-
 /**
  * Auxiliary function to display a formatted PDF version link
  *
  * Function made available so that developers may call this function from
  * their defined pages/blocks.
  *
- * @param $path
- *   path of the original page (optional). If not specified, the current URL
- *   is used
- * @param $node
- *   an optional node object, to be used in defining the path, if used, the
- *   path argument is irrelevant
- * @return
+ * @param string $path
+ *   path to be used in the link. If not specified, the current URL is used.
+ * @param object $node
+ *   node object, to be used in checking node access. If the path argument is
+ *   not provided, the path used will be node/nid.
+ * @param string $location
+ *   where in the page where the link is being inserted ('link', 'corner',
+ *   'block', 'help').
+ *
+ * @return bool
  *   string with the HTML link to the printer-friendly page
+ *
+ * @ingroup print_api
  */
-function print_pdf_insert_link($path = NULL, $node = NULL) {
-  if ($node !== NULL) {
-    $nid = $node->nid;
-    $path = 'node/' . $nid;
-    $allowed_type = print_pdf_link_allowed(array('node' => $node));
-  }
-  else {
-    if ($path === NULL) {
-      $nid = preg_replace('!^node/([\d]+)!', '$1', $_GET['q']);
-      $path = $_GET['q'];
-    }
-    else {
-      $nid = NULL;
-    }
-    $allowed_type = print_pdf_link_allowed(array('path' => $path));
-  }
-
-  if ($allowed_type) {
-    if ($nid !== NULL) {
-      if ($allowed_type === PRINT_ALLOW_BOOK_LINK) {
-        $path = 'book/export/html/' . $nid;
-      }
-      else {
-        if (variable_get('print_pdf_link_use_alias', PRINT_PDF_LINK_USE_ALIAS_DEFAULT) && ($alias = drupal_lookup_path('alias', $path))) {
-          $path = $alias;
-        }
-        else {
-          $path = $nid;
-        }
-      }
-      $path = PRINTPDF_PATH . '/' . $path;
-      $query = print_query_string_encode($_GET, array('q'));
-    }
-    else {
-      $query = NULL;
-    }
-    drupal_add_css(drupal_get_path('module', 'print') . '/css/printlinks.css');
-    $format = theme('print_pdf_format_link');
-    return '<span class="print_pdf">' . l($format['text'], $path, array('attributes' => $format['attributes'], 'query' => $query, 'absolute' => TRUE, 'html' => $format['html'])) . '</span>';
+function print_pdf_insert_link($path = NULL, $node = NULL, $location = '') {
+  if (function_exists('print_ui_insert_link')) {
+    return print_ui_insert_link(print_pdf_print_link(), array('path' => $path, 'node' => $node, 'location' => $location));
   }
   else {
     return FALSE;
@@ -581,135 +402,153 @@ function print_pdf_insert_link($path = NULL, $node = NULL) {
 /**
  * Check if the link to the PDF version is allowed depending on the settings
  *
- * @param $args
+ * @param array $args
  *   array containing the possible parameters:
- *    teaser, node, type, path
- * @return
- *   FALSE if not allowed
- *   PRINT_ALLOW_NORMAL_LINK if a normal link is allowed
- *   PRINT_ALLOW_BOOK_LINK if a link is allowed in a book node
+ *    view_mode, node, type, path
+ *
+ * @return bool
+ *   FALSE if not allowed, TRUE otherwise
  */
 function print_pdf_link_allowed($args) {
-  $view_mode = isset($args['view_mode']) ? $args['view_mode'] : '';
   $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
-  if ((($view_mode == 'teaser') && !variable_get('print_pdf_link_teaser', PRINT_PDF_LINK_TEASER_DEFAULT))
-      || !in_array($view_mode, array('full', 'teaser', '')) || !user_access('access PDF version') || (empty($print_pdf_pdf_tool))) {
-    // If the teaser link is disabled or the user is not allowed
-    return FALSE;
-  }
-  if (!empty($args['path'])) {
-    $nid = preg_replace('!^node/!', '', drupal_get_normal_path($args['path']));
-    if (ctype_digit($nid)) {
-      $args['node'] = node_load($nid);
-    }
-  }
-  if (!empty($args['node'])) {
-    static $node_type = FALSE;
 
-    $node = $args['node'];
-    if (isset($node->type)) {
-      $node_type = $node->type;
-    }
-    // Node
-    $print_pdf_node_link_visibility = variable_get('print_pdf_node_link_visibility', PRINT_PDF_NODE_LINK_VISIBILITY_DEFAULT);
-    $print_pdf_node_link_pages = variable_get('print_pdf_node_link_pages', PRINT_PDF_NODE_LINK_PAGES_DEFAULT);
+  return (user_access('access PDF version') && (!empty($print_pdf_pdf_tool)));
+}
 
-    if (!_print_page_match($print_pdf_node_link_visibility, "node/" . $node->nid, $print_pdf_node_link_pages)) {
-      // Page not in visibility list
-      return FALSE;
-    }
-    elseif (isset($args['type']) && ($args['type'] == 'comment') && isset($node_type)) {
-      // Link is for a comment, return the configured setting
-      // Cache this statically to avoid duplicate queries for every comment.
-      static $res = array();
-      if (!isset($res[$node->nid])) {
-        $res[$node->nid] = db_query("SELECT comments FROM {print_pdf_node_conf} WHERE nid = :nid", array(':nid' => $node->nid))->fetchField();
-      }
-      $print_display_comment = ($res && ($res[$node->nid] !== FALSE)) ? $res[$node->nid] : variable_get('print_pdf_display_comment_' . $node_type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
-      if ($print_display_comment) {
-        return PRINT_ALLOW_NORMAL_LINK;
+/**
+ * Implements hook_cron().
+ */
+function print_pdf_cron() {
+  print_pdf_cache_clean();
+}
+
+/**
+ * Removes pdf files for nodes/paths if they are older than the lifetime.
+ */
+function print_pdf_cache_clean() {
+  $lifetime = variable_get('print_pdf_cache_lifetime', PRINT_PDF_CACHE_LIFETIME_DEFAULT);
+
+  if ($lifetime > 0) {
+    $files = file_scan_directory(print_pdf_cache_dir(), '!\d+\.pdf$!');
+    foreach ($files as $file) {
+      // For all files in the cache directory, see when they were last accessed
+      $result = db_query("SELECT timestamp FROM {print_pdf_page_counter} WHERE path = :path", array(':path' => 'node/' . $file->name))
+                  ->fetchField();
+
+      // Keep the file only if the last access was within the cache max life value
+      if (($result === FALSE) || ($result + $lifetime < REQUEST_TIME)) {
+        print_pdf_cache_delete($file->name);
       }
     }
-    else {
-      // Node link
-      if (isset($node->print_pdf_display) && !$node->print_pdf_display) {
-        // Link for this node is disabled
-        return FALSE;
-      }
-      elseif (isset($node->book)) {
-        // Node is a book;
-        $print_pdf_book_link = variable_get('print_pdf_book_link', PRINT_PDF_BOOK_LINK_DEFAULT);
-        switch ($print_pdf_book_link) {
-          case 1:
-            if (user_access('access printer-friendly version')) {
-              return PRINT_ALLOW_BOOK_LINK;
-            }
-            break;
-          case 2:
-            return PRINT_ALLOW_NORMAL_LINK;
-        }
-      }
-      else {
-        return PRINT_ALLOW_NORMAL_LINK;
-      }
+  }
+}
+
+/**
+ * Returns the cache directory.
+ *
+ * @return string
+ *   The scheme://path of the cache directory
+ */
+function print_pdf_cache_dir() {
+  $scheme = 'private';
+  if (!file_stream_wrapper_valid_scheme($scheme)) {
+    $scheme = 'temporary';
+  }
+  return $scheme . '://print_pdf/cache';
+}
+
+/**
+ * Deletes one or more files from the PDF cache directory.
+ *
+ * @param int nid
+ *   The node ID of the page for which the cached PDF should be deleted.
+ *   If not provided, the entire cache directory will be deleted.
+ */
+function print_pdf_cache_delete($nid = NULL) {
+  $directory = print_pdf_cache_dir();
+
+  if ($nid) {
+    $filename = $directory . '/' . $nid . '.pdf';
+    if (is_file($filename)) {
+      file_unmanaged_delete($filename);
     }
   }
   else {
-    // 'System' page
-    $print_pdf_sys_link_visibility = variable_get('print_pdf_sys_link_visibility', PRINT_PDF_SYS_LINK_VISIBILITY_DEFAULT);
-    $print_pdf_sys_link_pages = variable_get('print_pdf_sys_link_pages', PRINT_PDF_SYS_LINK_PAGES_DEFAULT);
-
-    return _print_page_match($print_pdf_sys_link_visibility, $_GET['q'], $print_pdf_sys_link_pages);
+    // If no nid is provided, flush the entire cache.
+    if (is_dir($directory)) {
+      file_unmanaged_delete_recursive($directory);
+    }
   }
-  return FALSE;
 }
 
 /**
- * Find out the version of the TCPDF library
+ * Displays the PDF as inline or a downloadable file.
+ *
+ * @param string $pdf
+ *   PDF content string
+ * @param string $filename
+ *   Filename of the generated PDF
+ *
+ * @return string
+ *   The disposed PDF file
  */
-function _print_pdf_tcpdf_version() {
-  $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
-  if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
-    // prevent TCPDF default configs
-    define('K_TCPDF_EXTERNAL_CONFIG', TRUE);
+function print_pdf_dispose_content($pdf, $filename) {
+  if (headers_sent()) {
+    exit('Unable to stream pdf: headers already sent');
   }
-  require_once(DRUPAL_ROOT . '/' . $print_pdf_pdf_tool);
+  header('Cache-Control: private');
+  header('Content-Type: application/pdf');
 
-  // Hide warnings, as some TCPDF constants may still be undefined
-  @$pdf = new TCPDF();
+  $content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
+  $attachment =  ($content_disposition == 2) ?  'attachment' :  'inline';
 
-  if (method_exists($pdf, 'getTCPDFVersion')) {
-    return $pdf->getTCPDFVersion();
-  }
-  elseif (defined('PDF_PRODUCER')) {
-    sscanf(PDF_PRODUCER, "TCPDF %s", $version);
+  header("Content-Disposition: $attachment; filename=\"$filename\"");
 
-    return $version;
-  }
-  else {
-    return 'unknown';
-  }
+  echo $pdf;
+  flush();
+
+  return TRUE;
 }
 
 /**
- * Find out the version of the wkhtmltopdf library
+ * Generate a PDF version of the provided HTML.
+ *
+ * @param string $html
+ *   HTML content of the PDF
+ * @param array $meta
+ *   Meta information to be used in the PDF
+ *   - url: original URL
+ *   - name: author's name
+ *   - title: Page title
+ *   - node: node object
+ * @param string $filename
+ *   (optional) Filename of the generated PDF
+ * @param string $paper_size
+ *   (optional) Paper size of the generated PDF
+ * @param string $page_orientation
+ *   (optional) Page orientation of the generated PDF
+ *
+ * @return
+ *   generated PDF page, or NULL in case of error
+ *
+ * @see print_pdf_controller()
+ *
+ * @ingroup print_api
  */
-function _print_pdf_wkhtmltopdf_version() {
-  $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
-  $descriptor = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
-
-  $cmd = '"' . realpath($print_pdf_pdf_tool) . '" --version';
-  $process = proc_open($cmd, $descriptor, $pipes, NULL, NULL);
-  if (is_resource($process)) {
-    $content = stream_get_contents($pipes[1]);
-    $out = preg_match('!.*?(\d+\.\d+\.\d+).*$!m', $content, $matches);
-    fclose($pipes[0]);
-    fclose($pipes[1]);
-    fclose($pipes[2]);
-    $retval = proc_close($process);
+function print_pdf_generate_html($html, $meta, $filename = NULL, $paper_size = NULL, $page_orientation = NULL) {
+  $pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
+
+  module_load_include('inc', $pdf_tool[0], $pdf_tool[0] . '.pages');
+
+  $function = $pdf_tool[0] . '_print_pdf_generate';
+  if (function_exists($function)) {
+    $pdf = $function($html, $meta, $paper_size, $page_orientation);
+  }
+  if ($filename) {
+    return print_pdf_dispose_content($pdf, $filename);
   }
 
-  return ($matches[1]);
+  return $pdf;
 }
 
 /**
@@ -721,3 +560,34 @@ function print_pdf_views_api() {
     'path' => drupal_get_path('module', 'print_pdf'),
   );
 }
+
+/**
+ * Lists all possible paper sizes
+ *
+ * @return
+ *   array of strings with the available paper sizes
+ */
+function _print_pdf_paper_sizes($include_default = FALSE) {
+  $ret = array();
+
+  $ret = ($include_default) ? array('' => 'Unchanged') : array();
+
+  $ret += array(
+    '4A0' => '4A0', '2A0' => '2A0', 'A0' => 'A0',
+    'A1' => 'A1', 'A2' => 'A2', 'A3' => 'A3', 'A4' => 'A4',
+    'A5' => 'A5', 'A6' => 'A6', 'A7' => 'A7', 'A8' => 'A8',
+    'A9' => 'A9', 'A10' => 'A10', 'B0' => 'B0', 'B1' => 'B1',
+    'B2' => 'B2', 'B3' => 'B3', 'B4' => 'B4', 'B5' => 'B5',
+    'B6' => 'B6', 'B7' => 'B7', 'B8' => 'B8', 'B9' => 'B9',
+    'B10' => 'B10', 'C0' => 'C0', 'C1' => 'C1', 'C2' => 'C2',
+    'C3' => 'C3', 'C4' => 'C4', 'C5' => 'C5', 'C6' => 'C6',
+    'C7' => 'C7', 'C8' => 'C8', 'C9' => 'C9', 'C10' => 'C10',
+    'RA0' => 'RA0', 'RA1' => 'RA1', 'RA2' => 'RA2',
+    'RA3' => 'RA3', 'RA4' => 'RA4', 'SRA0' => 'SRA0',
+    'SRA1' => 'SRA1', 'SRA2' => 'SRA2', 'SRA3' => 'SRA3',
+    'SRA4' => 'SRA4', 'LETTER' => 'Letter', 'LEGAL' => 'Legal',
+    'EXECUTIVE' => 'Executive', 'FOLIO' => 'Folio',
+  );
+
+  return $ret;
+}

+ 80 - 530
sites/all/modules/contrib/admin/print/print_pdf/print_pdf.pages.inc

@@ -44,12 +44,12 @@ function print_pdf_controller() {
 
     $pdf_filename = variable_get('print_pdf_filename', PRINT_PDF_FILENAME_DEFAULT);
     if (!empty($pdf_filename) && !empty($node)) {
-      $pdf_filename = token_replace($pdf_filename, array('node' => $node));
+      $pdf_filename = token_replace($pdf_filename, array('node' => $node), array('clear' => TRUE));
     }
     else {
-      $pdf_filename = token_replace($pdf_filename, array('site'));
-      if (empty($pdf_filename) || count(token_scan($pdf_filename))) {
-        // If there are still tokens, use a fallback solution
+      $pdf_filename = token_replace($pdf_filename, array('site'), array('clear' => TRUE));
+      if (empty($pdf_filename)) {
+        // If empty, use a fallback solution
         $pdf_filename = str_replace('/', '_', $path);
       }
     }
@@ -70,7 +70,7 @@ function print_pdf_controller() {
     exit;
   }
 
-  $nodepath = (isset($node->path) && is_string($node->path)) ? drupal_get_normal_path($node->path) : 'node/' . $path;
+  $nodepath = (isset($node->nid)) ? 'node/' . $node->nid : drupal_get_normal_path($path);
   db_merge('print_pdf_page_counter')
     ->key(array('path' => $nodepath))
     ->fields(array(
@@ -83,548 +83,98 @@ function print_pdf_controller() {
   drupal_exit();
 }
 
-function print_pdf_generate_path($path, $query = NULL, $cid = NULL, $pdf_filename = NULL) {
-  global $base_url;
-
-  $print = print_controller($path, $query, $cid, PRINT_PDF_FORMAT);
-  if ($print === FALSE) {
-    return;
-  }
-
-  // Img elements must be set to absolute
-  $pattern = '!<(img\s[^>]*?)>!is';
-  $print['content'] = preg_replace_callback($pattern, '_print_rewrite_urls', $print['content']);
-  $print['logo'] = preg_replace_callback($pattern, '_print_rewrite_urls', $print['logo']);
-  $print['footer_message'] = preg_replace_callback($pattern, '_print_rewrite_urls', $print['footer_message']);
-
-  // Send to printer option causes problems with PDF
-  $print['sendtoprinter'] = '';
-
-  $node = $print['node'];
-  $html = theme('print', array('print' => $print, 'type' => PRINT_PDF_FORMAT, 'node' => $node));
-
-  // Convert the a href elements, to make sure no relative links remain
-  $pattern = '!<(a\s[^>]*?)>!is';
-  $html = preg_replace_callback($pattern, '_print_rewrite_urls', $html);
-  // And make anchor links relative again, to permit in-PDF navigation
-  $html = preg_replace("!${base_url}/" . PRINTPDF_PATH . '/.*?#!', '#', $html);
-
-  return print_pdf_generate_html($print, $html, $pdf_filename);
-}
-
-function print_pdf_generate_html($print, $html, $filename = NULL) {
-  $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
-
-  if (basename($print_pdf_pdf_tool) == 'dompdf_config.inc.php') {
-    return _print_pdf_dompdf($print, $html, $filename);
-  }
-  elseif (basename($print_pdf_pdf_tool) == 'tcpdf.php') {
-    return _print_pdf_tcpdf($print, $html, $filename);
-  }
-  elseif (drupal_substr(basename($print_pdf_pdf_tool, '.exe'), 0, 11) == 'wkhtmltopdf') {
-    return _print_pdf_wkhtmltopdf($print, $html, $filename);
-  }
-  elseif ($filename) {
-    return drupal_not_found();
-  }
-  return NULL;
-}
-
 /**
- * Convert image paths to the file:// protocol
+ * Gennerate a PDF for a given Drupal path.
  *
- * In some Drupal setups, the use of the 'private' filesystem or Apache's
- * configuration prevent access to the images of the page. This function
- * tries to circumnvent those problems by accessing files in the local
- * filesystem.
+ * @param string $path
+ *   path of the page to convert to PDF
+ * @param array $query
+ *   (optional) array of key/value pairs as used in the url() function for the
+ *   query
+ * @param int $cid
+ *   (optional) comment ID of the comment to render.
+ * @param string $pdf_filename
+ *   (optional) filename of the generated PDF
+ * @param string $view_mode
+ *   (optional) view mode to be used when rendering the content
  *
- * @param $html
- *   contents of the post-processed template already with the node data
- * @see print_pdf_controller()
- */
-function _print_pdf_file_access_images($html) {
-  global $base_url, $language;
-  $print_pdf_images_via_file = variable_get('print_pdf_images_via_file', PRINT_PDF_IMAGES_VIA_FILE_DEFAULT);
-
-  $lang = (function_exists('language_negotiation_get_any') && language_negotiation_get_any('locale-url')) ? $language->language : '';
-
-  // Always convert private to local paths
-  $pattern = "!(<img\s[^>]*?src\s*?=\s*?['\"]?)${base_url}/(?:(?:index.php)?\?q=)?(?:${lang}/)?system/files/([^>]*?>)!is";
-  $replacement = '$1file://' . realpath(variable_get('file_private_path', '')) . '/$2';
-  $html = preg_replace($pattern, $replacement, $html);
-  if ($print_pdf_images_via_file) {
-    $pattern = "!(<img\s[^>]*?src\s*?=\s*?['\"]?)${base_url}/(?:(?:index.php)?\?q=)?(?:${lang}/)?([^>]*?>)!is";
-    $replacement = '$1file://' . dirname($_SERVER['SCRIPT_FILENAME']) . '/$2';
-    $html = preg_replace($pattern, $replacement, $html);
-  }
-
-  return $html;
-}
-
-/**
- * Generate the PDF file using the dompdf library
+ * @return
+ *   generated PDF page, or NULL in case of error
  *
- * @param $print
- *   array containing the configured data
- * @param $html
- *   contents of the post-processed template already with the node data
- * @param $filename
- *   name of the PDF file to be generated
  * @see print_pdf_controller()
  */
-function _print_pdf_dompdf($print, $html, $filename = NULL) {
-  $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
-  $print_pdf_paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT);
-  $print_pdf_page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT);
-  $print_pdf_content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
-
-  if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
-    define("DOMPDF_ENABLE_PHP", FALSE);
-    define("DOMPDF_ENABLE_REMOTE", TRUE);
-    define("DOMPDF_TEMP_DIR", file_directory_temp());
-    define("DOMPDF_UNICODE_ENABLED", variable_get('print_pdf_dompdf_unicode', PRINT_PDF_DOMPDF_UNICODE_DEFAULT));
-    define("DOMPDF_FONT_CACHE", drupal_realpath('public://' . PRINT_PDF_DOMPDF_CACHE_DIR_DEFAULT . '/fonts/'));
-  }
-
-  require_once(DRUPAL_ROOT . '/' . $print_pdf_pdf_tool);
-  spl_autoload_register('DOMPDF_autoload');
-
-  // Try to use local file access for image files
-  $html = _print_pdf_file_access_images($html);
-
-  // Spaces in img URLs must be replaced with %20
-  $pattern = '!<(img\s[^>]*?)>!is';
-  $html = preg_replace_callback($pattern, '_print_replace_spaces', $html);
-
-  // dompdf seems to have problems with something in system.css so let's not use it
-  $html = preg_replace('!<link.*?modules/system/system.css.*?/>!', '', $html);
-
-  $url_array  = parse_url($print['url']);
-
-  $protocol = $url_array['scheme'] . '://';
-  $host = $url_array['host'];
-  $path = dirname($url_array['path']) . '/';
-
-  $dompdf = new DOMPDF();
-  $dompdf->set_base_path($path);
-  $dompdf->set_host($host);
-  $dompdf->set_paper(drupal_strtolower($print_pdf_paper_size), $print_pdf_page_orientation);
-  $dompdf->set_protocol($protocol);
-
-// dompdf can't handle footers cleanly, so disable the following
-//  $html = theme('print_pdf_dompdf_footer', array('html' => $html));
-
-  // If dompdf Unicode support is disabled, try to convert to ISO-8859-1 and then to HTML entities
-  if (!variable_get('print_pdf_dompdf_unicode', PRINT_PDF_DOMPDF_UNICODE_DEFAULT)) {
-  // Convert the euro sign to an HTML entity
-  $html = str_replace('€', '&#0128;', $html);
-
-  // Convert from UTF-8 to ISO 8859-1 and then to HTML entities
-  if (function_exists('utf8_decode')) {
-    $html = utf8_decode($html);
-  }
-// iconv fails silently when it encounters something that it doesn't know, so don't use it
-//  else if (function_exists('iconv')) {
-//    $html = iconv('UTF-8', 'ISO-8859-1', $html);
-//  }
-  elseif (function_exists('mb_convert_encoding')) {
-    $html = mb_convert_encoding($html, 'ISO-8859-1', 'UTF-8');
-  }
-  elseif (function_exists('recode_string')) {
-    $html = recode_string('UTF-8..ISO_8859-1', $html);
-  }
-  $html = htmlspecialchars_decode(htmlentities($html, ENT_NOQUOTES, 'ISO-8859-1'), ENT_NOQUOTES);
-  }
-
-  // Must get rid of tbody (dompdf goes into recursion)
-  $html = preg_replace('!<tbody[^>]*?>|</tbody>!i', '', $html);
-
-  $dompdf->load_html($html);
-
-  $dompdf->render();
-  if ($filename) {
-    $dompdf->stream($filename, array('Attachment' => ($print_pdf_content_disposition == 2)));
-    return TRUE;
-  }
-  else {
-    return $dompdf->output();
-  }
-}
-
-/**
- * Generate the PDF file using the TCPDF library
- *
- * @param $print
- *   array containing the configured data
- * @param $html
- *   contents of the post-processed template already with the node data
- * @param $filename
- *   name of the PDF file to be generated
- * @see print_pdf_controller()
- */
-function _print_pdf_tcpdf($print, $html, $filename = NULL) {
-  global $base_url, $language;
-
-  $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
-  $print_pdf_paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT);
-  $print_pdf_page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT);
-  $print_pdf_content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
-
-  $pdf_tool_path = realpath(dirname($print_pdf_pdf_tool));
-
-  if (variable_get('print_pdf_autoconfig', PRINT_PDF_AUTOCONFIG_DEFAULT)) {
-    define('K_TCPDF_EXTERNAL_CONFIG', TRUE);
-    define('K_PATH_MAIN', dirname($_SERVER['SCRIPT_FILENAME']));
-    define('K_PATH_URL', $base_url);
-    define('K_PATH_FONTS', $pdf_tool_path . '/fonts/');
-    define('K_PATH_CACHE', drupal_realpath('public://' . PRINT_PDF_TCPDF_CACHE_DIR_DEFAULT . '/cache/'));
-    define('K_PATH_IMAGES', '');
-    define('K_BLANK_IMAGE', $pdf_tool_path . '/images/_blank.png');
-    define('K_CELL_HEIGHT_RATIO', 1.25);
-    define('K_SMALL_RATIO', 2/3);
-  }
-
-  // Try to use local file access for image files
-  $html = _print_pdf_file_access_images($html);
-
-  // Decode HTML entities in image filenames
-  $pattern = "!<img\s[^>]*?src\s*?=\s*?['\"]?{$base_url}[^>]*?>!is";
-  $html = preg_replace_callback($pattern, create_function('$matches', 'return html_entity_decode($matches[0], ENT_QUOTES);'), $html);
-  // Remove queries from the image URL
-  $pattern = "!(<img\s[^>]*?src\s*?=\s*?['\"]?{$base_url}[^>]*?)(?:%3F|\?)[\w=&]+([^>]*?>)!is";
-  $html = preg_replace($pattern, '$1$2', $html);
-
-  require_once(DRUPAL_ROOT . '/' . $print_pdf_pdf_tool);
-  module_load_include('inc', 'print_pdf', 'print_pdf.class');
-
-  $font = Array(
-    check_plain(variable_get('print_pdf_font_family', PRINT_PDF_FONT_FAMILY_DEFAULT)),
-    '',
-    check_plain(variable_get('print_pdf_font_size', PRINT_PDF_FONT_SIZE_DEFAULT)),
-  );
-  $orientation = drupal_strtoupper($print_pdf_page_orientation[0]);
-
-  // create new PDF document
-  $pdf = new PrintTCPDF($orientation , 'mm', $print_pdf_paper_size, TRUE);
-
-  // set document information
-  if (property_exists($print['node'], 'name')) {
-    $pdf->SetAuthor(strip_tags($print['node']->name));
-  }
-  $pdf->SetCreator(variable_get('site_name', 'Drupal'));
-  $pdf->SetTitle(html_entity_decode($print['title'], ENT_QUOTES, 'UTF-8'));
-  $pdf->setPDFVersion('1.6');
-  $pdf->setFontSubsetting(variable_get('print_pdf_font_subsetting', PRINT_PDF_FONT_SUBSETTING_DEFAULT));
-
-  if ($language->direction == LANGUAGE_RTL) {
-    $pdf->setRTL(TRUE);
-  }
-
-  $pdf = theme('print_pdf_tcpdf_header', array('pdf' => $pdf, 'html' => $html, 'font' => $font));
-  $pdf = theme('print_pdf_tcpdf_footer', array('pdf' => $pdf, 'html' => $html, 'font' => $font));
-  $pdf = theme('print_pdf_tcpdf_page', array('pdf' => $pdf));
-
-  // add a page
-  $pdf->AddPage();
-
-  $pdf = theme('print_pdf_tcpdf_content', array('pdf' => $pdf, 'html' => $html, 'font' => $font));
-
-  // reset pointer to the last page
-  $pdf->lastPage();
-
-  // try to recover from any warning/error
-  ob_clean();
-
-  if ($filename) {
-    // Close and output PDF document
-    $output_dest = ($print_pdf_content_disposition == 2) ? 'D' : 'I';
-    $pdf->Output($filename, $output_dest);
-    return TRUE;
-  }
-  else {
-    return $pdf = $pdf->Output('', 'S');
-  }
-}
-
-/**
- * Generate the PDF file using wkhtmltopdf
- *
- * @param $print
- *   array containing the configured data
- * @param $html
- *   contents of the post-processed template already with the node data
- * @param $filename
- *   name of the PDF file to be generated
- * @see print_pdf_controller()
- */
-function _print_pdf_wkhtmltopdf($print, $html, $filename = NULL) {
-  $print_pdf_pdf_tool = variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT);
-  $print_pdf_paper_size = variable_get('print_pdf_paper_size', PRINT_PDF_PAPER_SIZE_DEFAULT);
-  $print_pdf_page_orientation = variable_get('print_pdf_page_orientation', PRINT_PDF_PAGE_ORIENTATION_DEFAULT);
-  $print_pdf_content_disposition = variable_get('print_pdf_content_disposition', PRINT_PDF_CONTENT_DISPOSITION_DEFAULT);
-  $print_pdf_wkhtmltopdf_options = variable_get('print_pdf_wkhtmltopdf_options', PRINT_PDF_WKHTMLTOPDF_OPTIONS);
-
-  $dpi = 96;
-
-  if (!empty($print_pdf_wkhtmltopdf_options)) {
-    $print_pdf_wkhtmltopdf_options = token_replace($print_pdf_wkhtmltopdf_options, array('node' => $print['node']));
-  }
-
-  $version = _print_pdf_wkhtmltopdf_version();
-
-  // 0.10.0 beta2 identifies itself as 0.9.9
-  if (version_compare($version, '0.9.9', '>=')) {
-    $print_pdf_wkhtmltopdf_options = '--disable-local-file-access ' . $print_pdf_wkhtmltopdf_options;
-  }
-  elseif (version_compare($version, '0.9.6', '>=')) {
-    $print_pdf_wkhtmltopdf_options = '--disallow-local-file-access ' . $print_pdf_wkhtmltopdf_options;
-  }
-  else {
-    drupal_goto($print['url']);
-    exit;
-  }
-
-  $descriptor = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'a'));
-  $cmd = '"' . realpath($print_pdf_pdf_tool) . "\" --page-size $print_pdf_paper_size --orientation $print_pdf_page_orientation --dpi $dpi $print_pdf_wkhtmltopdf_options - -";
-
-  $process = proc_open($cmd, $descriptor, $pipes, NULL, NULL);
-
-  if (is_resource($process)) {
-    fwrite($pipes[0], $html);
-    fclose($pipes[0]);
-
-    $pdf = stream_get_contents($pipes[1]);
-    fclose($pipes[1]);
+function print_pdf_generate_path($path, $query = NULL, $cid = NULL, $pdf_filename = NULL, $view_mode = PRINT_VIEW_MODE) {
+  global $base_url;
 
-    stream_set_blocking($pipes[2], 0);
-    $error = stream_get_contents($pipes[2]);
-    fclose($pipes[2]);
+  $link = print_pdf_print_link();
+  $node = print_controller($path, $link['format'], $cid, $view_mode);
+  if ($node) {
+    // Call the current tool's hook_pdf_tool_info(), to see if we need to expand CSS
+    $pdf_tool = explode('|', variable_get('print_pdf_pdf_tool', PRINT_PDF_PDF_TOOL_DEFAULT));
+    $cache_enabled = variable_get('print_pdf_cache_enabled', PRINT_PDF_CACHE_ENABLED_DEFAULT);
 
-    $retval = proc_close($process);
-    if (!empty($error) || ($retval != 0)) {
-      if (empty($error)) {
-        $error = 'No stderr output available.';
-      }
-      watchdog('print_pdf', "wkhtmltopdf (returned $retval): $error");
+    $function = $pdf_tool[0] . '_pdf_tool_info';
+    if (function_exists($function)) {
+      $info = $function();
     }
-  }
-
-  if (!empty($pdf)) {
-    if ($filename) {
-      if (headers_sent()) {
-        exit("Unable to stream pdf: headers already sent");
+    $expand = isset($info['expand_css']) ? $info['expand_css'] : FALSE;
+
+    $html = theme('print', array('node' => $node, 'query' => $query, $expand, 'format' => $link['format']));
+
+    // Img elements must be set to absolute
+    $pattern = '!<(img\s[^>]*?)>!is';
+    $html = preg_replace_callback($pattern, '_print_rewrite_urls', $html);
+
+    // Convert the a href elements, to make sure no relative links remain
+    $pattern = '!<(a\s[^>]*?)>!is';
+    $html = preg_replace_callback($pattern, '_print_rewrite_urls', $html);
+    // And make anchor links relative again, to permit in-PDF navigation
+    $html = preg_replace("!${base_url}/" . $link['path'] . '/.*?#!', '#', $html);
+
+    $meta = array(
+      'node' => $node,
+      'url' => url(drupal_get_path_alias(empty($node->nid) ? $node->path : "node/$node->nid"), array('absolute' => TRUE)),
+    );
+    if (isset($node->name)) $meta['name'] = $node->name;
+    if (isset($node->title)) $meta['title'] = $node->title;
+
+    $paper_size = isset($node->print_pdf_size) ? $node->print_pdf_size : NULL;
+    $page_orientation = isset($node->print_pdf_orientation) ? $node->print_pdf_orientation : NULL;
+
+    $pdf = '';
+    $cachemiss = FALSE;
+    if ($cache_enabled && isset($node->nid)) {
+      // See if the file exists in the cache
+      $cachefile = drupal_realpath(print_pdf_cache_dir()) . '/' . $node->nid . '.pdf';
+      if (is_readable($cachefile)) {
+        // Get the PDF content from the cached file
+        $pdf = file_get_contents($cachefile);
+        if ($pdf === FALSE) {
+          watchdog('print_pdf', 'Failed to read from cached file %file', array('%file' => $cached), WATCHDOG_ERROR);
+        }
+      }
+      else {
+        $cachemiss = TRUE;
       }
-      header("Cache-Control: private");
-      header("Content-Type: application/pdf");
-
-      $attachment =  ($print_pdf_content_disposition == 2) ?  "attachment" :  "inline";
-
-      header("Content-Disposition: $attachment; filename=\"$filename\"");
-
-      echo $pdf;
-      flush();
-      return TRUE;
-    }
-    else {
-      return $pdf;
     }
-  }
-  else {
-    drupal_set_message(t('Unable to generate PDF file.'), 'error');
-    drupal_goto($meta['url']);
-    return NULL;
-  }
-}
-
-/**
- * Format the dompdf footer contents
- *
- * @param $html
- *   contents of the body of the HTML from the original node
- * @see theme_print_pdf_tcpdf_footer()
- */
-function theme_print_pdf_dompdf_footer($vars) {
-  preg_match('!<div class="print-footer">(.*?)</div>!si', $vars['html'], $tpl_footer);
-  $html = str_replace($tpl_footer[0], '', $vars['html']);
-
-  $text = '<script type="text/php">
-    if (isset($pdf)) {
-      $font = Font_Metrics::get_font("verdana");;
-      $size = 10;
-      $color = array(0,0,0);
-      $text_height = Font_Metrics::get_font_height($font, $size);
-
-      $w = $pdf->get_width();
-      $h = $pdf->get_height();
-
-      $footer = $pdf->open_object();
-
-      // Draw a line along the bottom
-      $y = $h - 25;
-      $pdf->line(15, $y, $w - 15, $y, $color, 1);
-
-      $y += $text_height / 2;
-      $pdf->page_text(15, $y, \'' . addslashes(strip_tags($tpl_footer[1])) . '\', $font, $size, $color);
-
-      $pdf->close_object();
-      $pdf->add_object($footer, "all");
 
-      // Center the text
-      $width = Font_Metrics::get_text_width("Page 1 of 2", $font, $size);
-      $pagenumtxt = t("Page !n of !total", array("!n" => "{PAGE_NUM}", "!total" => "{PAGE_COUNT}"));
-      $pdf->page_text($w - 15 - $width, $y, $pagenumtxt, $font, $size, $color);
+    // If cache is off or file is not cached, generate one from scratch
+    if (empty($pdf)) {
+      $pdf = print_pdf_generate_html($html, $meta, NULL, $paper_size, $page_orientation);
     }
-  </script>';
 
-  return str_replace("<body>", "<body>" . $text, $html);
-}
-
-/**
- * Format the TCPDF header
- *
- * @param $pdf
- *   current TCPDF object
- * @param $html
- *   contents of the body of the HTML from the original node
- * @param $font
- *   array with the font definition (font name, styles and size)
- * @see theme_print_pdf_tcpdf_header()
- */
-function theme_print_pdf_tcpdf_header($vars) {
-  $pdf = $vars['pdf'];
-  preg_match('!<div class="print-logo">(.*?)</div>!si', $vars['html'], $tpl_logo);
-  preg_match('!<title>(.*?)</title>!si', $vars['html'], $tpl_title);
-  preg_match('!<div class="print-site_name">(.*?)</div>!si', $vars['html'], $tpl_site_name);
+    if (!empty($pdf)) {
+      // A PDF was created, save it to cache if configured
+      if ($cachemiss) {
+        if (file_unmanaged_save_data($pdf, $cachefile, FILE_EXISTS_REPLACE) == FALSE) {
+          watchdog('print_pdf', 'Failed to write to "%f".', array('%f' => $filename), WATCHDOG_ERROR);
+        }
+      }
 
-  $ratio = 0;
-  $logo = '';
-  if (isset($tpl_logo[1]) && preg_match('!src\s*=\s*(?:"(.*?)"|\'(.*?)\'|([^\s]*))!i', $tpl_logo[1], $logo_url)) {
-    $logo = $logo_url[1];
-    if (!empty($logo)) {
-      $size = getimagesize($logo);
-      $ratio = $size ? ($size[0] / $size[1]) : 0;
+      return $pdf_filename ? print_pdf_dispose_content($pdf, $pdf_filename) : $pdf;
     }
   }
-
-  // set header font
-  $pdf->setHeaderFont($vars['font']);
-  // set header margin
-  $pdf->setHeaderMargin(5);
-  // set header data
-  $pdf->setHeaderData($logo, 10 * $ratio, html_entity_decode($tpl_title[1], ENT_QUOTES, 'UTF-8'), html_entity_decode(strip_tags($tpl_site_name[1]), ENT_QUOTES, 'UTF-8'));
-
-  return $pdf;
-}
-
-/**
- * Format the TCPDF page settings (margins, etc)
- *
- * @param $pdf
- *   current TCPDF object
- * @see theme_print_pdf_tcpdf_page()
- */
-function theme_print_pdf_tcpdf_page($vars) {
-  $pdf = $vars['pdf'];
-  // set margins
-  $pdf->SetMargins(15, 20, 15);
-  // set auto page breaks
-  $pdf->SetAutoPageBreak(TRUE, 15);
-  // set image scale factor
-  $pdf->setImageScale(1);
-  // set image compression quality
-  $pdf->setJPEGQuality(100);
-
-  return $pdf;
-}
-
-/**
- * Format the TCPDF page content
- *
- * @param $pdf
- *   current TCPDF object
- * @param $html
- *   contents of the body of the HTML from the original node
- * @param $font
- *   array with the font definition (font name, styles and size)
- * @see theme_print_pdf_tcpdf_content()
- */
-function theme_print_pdf_tcpdf_content($vars) {
-  $pdf = $vars['pdf'];
-  // set content font
-  $pdf->setFont($vars['font'][0], $vars['font'][1], $vars['font'][2]);
-
-  preg_match('!<body.*?>(.*)</body>!sim', $vars['html'], $matches);
-  $pattern = '!(?:<div class="print-(?:logo|site_name|breadcrumb|footer)">.*?</div>|<hr class="print-hr" />)!si';
-  $matches[1] = preg_replace($pattern, '', $matches[1]);
-
-  // Make CCK fields look better
-  $matches[1] = preg_replace('!(<div class="field.*?>)\s*!sm', '$1', $matches[1]);
-  $matches[1] = preg_replace('!(<div class="field.*?>.*?</div>)\s*!sm', '$1', $matches[1]);
-  $matches[1] = preg_replace('!<div( class="field-label.*?>.*?)</div>!sm', '<strong$1</strong>', $matches[1]);
-
-  // Since TCPDF's writeHTML is so bad with <p>, do everything possible to make it look nice
-  $matches[1] = preg_replace('!<(?:p(|\s+.*?)/?|/p)>!i', '<br$1 />', $matches[1]);
-  $matches[1] = str_replace(array('<div', 'div>'), array('<span', 'span><br />'), $matches[1]);
-  do {
-    $prev = $matches[1];
-    $matches[1] = preg_replace('!(</span>)<br />(\s*?</span><br />)!s', '$1$2', $matches[1]);
-  } while ($prev != $matches[1]);
-
-  @$pdf->writeHTML($matches[1]);
-
-  return $pdf;
-}
-
-/**
- * Format the TCPDF footer contents
- *
- * @param $pdf
- *   current TCPDF object
- * @param $html
- *   contents of the body of the HTML from the original node
- * @param $font
- *   array with the font definition (font name, styles and size)
- * @see theme_print_pdf_tcpdf_footer()
- */
-function theme_print_pdf_tcpdf_footer($vars) {
-  $pdf = $vars['pdf'];
-  preg_match('!<div class="print-footer">(.*?)</div>!si', $vars['html'], $tpl_footer);
-  $footer = trim(preg_replace('!</?div[^>]*?>!i', '', $tpl_footer[1]));
-
-  // set footer font
-  $vars['font'][2] *= 0.8;
-  $pdf->setFooterFont($vars['font']);
-  // set footer margin
-  $pdf->SetFooterMargin(10);
-  // set footer data
-  $pdf->SetFooterData($footer);
-
-  return $pdf;
-}
-
-/**
- * Format the TCPDF footer layout
- *
- * @param $pdf
- *   current TCPDF object
- * @see theme_print_pdf_tcpdf_footer2()
- */
-function theme_print_pdf_tcpdf_footer2($vars) {
-  $pdf = $vars['pdf'];
-  // Position at 1.5 cm from bottom
-  $pdf->writeHTMLCell(0, 15, 15, $pdf->getPageHeight()-15, $pdf->footer);
-
-  $ormargins = $pdf->getOriginalMargins();
-  $pagenumtxt = t('Page !n of !total', array('!n' => $pdf->PageNo(), '!total' => $pdf->getAliasNbPages()));
-  // Print page number
-  if ($pdf->getRTL()) {
-    $pdf->SetX($ormargins['right']);
-    $pdf->Cell(0, 10, $pagenumtxt, 'T', 0, 'L');
-  }
   else {
-    $pdf->SetX($ormargins['left']);
-    $pdf->Cell(0, 10, $pagenumtxt, 'T', 0, 'R');
+    return NULL;
   }
-
-  return $pdf;
 }

+ 29 - 1
sites/all/modules/contrib/admin/print/print_pdf/print_pdf.views.inc

@@ -33,7 +33,7 @@ function print_pdf_views_data() {
     'left_field' => 'nid',
     'field' => 'path',
 //    'type' => 'INNER',
-    'handler' => 'print_pdf_join_page_counter',
+    'handler' => 'print_join_page_counter',
   );
 
   // print_pdf_node_conf fields
@@ -85,6 +85,34 @@ function print_pdf_views_data() {
       'handler' => 'views_handler_sort',
     ),
   );
+  $data['print_pdf_node_conf']['size'] = array(
+    'title' => t('PDF: Paper size'),
+    'help' => t('Configured PDF paper size'),
+    'field' => array(
+      'handler' => 'views_handler_field',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['print_pdf_node_conf']['orientation'] = array(
+    'title' => t('PDF: Page orientation'),
+    'help' => t('Configured PDF page orientation.'),
+    'field' => array(
+      'handler' => 'views_handler_field',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
 
 
   // print_pdf_page_counter fields

+ 2 - 7
sites/all/modules/contrib/admin/print/css/printlinks-rtl.css → sites/all/modules/contrib/admin/print/print_ui/css/print_ui.theme-rtl.css

@@ -1,14 +1,13 @@
-
 .print-link {
   /* Use these for links above the content */
   text-align: left;
   /* Use these for links in a corner of the content */
   /*
-  float:left;
+  float: left;
   */
 }
 
-.print_html, .print_mail, .print_pdf {
+.print_html, .print_mail, .print_pdf, .print_epub {
   margin-left: 0;
   margin-right: 1em;
 }
@@ -21,7 +20,3 @@
 img.print-icon-margin {
   padding-left: 4px;
 }
-
-label.printmail-label {
-  float: right;
-}

Some files were not shown because too many files changed in this diff