SA-CONTRIB-2009-052: remove multiple XSS vulnerabilities
[project/print.git] / print.module
1 <?php
2 // $Id$
3
4 /**
5 * @defgroup print Printer, e-mail and PDF versions
6 *
7 * Welcome to the print module developer's documentation. The interesting
8 * functions for themers are those that start with 'theme_'.
9 *
10 * - Printer-friendly pages
11 * - @link print.module Module main file @endlink
12 * - @link print.admin.inc Settings form @endlink
13 * - @link print.pages.inc HTML generation @endlink
14 * - @link print.install (Un)Install routines @endlink
15 * - @link print.tpl.php Page generation template @endlink
16 * - Send by e-mail
17 * - @link print_mail.module Module main file @endlink
18 * - @link print_mail.admin.inc Settings form @endlink
19 * - @link print_mail.inc Mail form and send mail routine @endlink
20 * - @link print_mail.install (Un)Install routines @endlink
21 * - PDF version
22 * - @link print_pdf.module Module main file @endlink
23 * - @link print_pdf.admin.inc Settings form @endlink
24 * - @link print_pdf.pages.inc PDF generation @endlink
25 * - @link print_pdf.class.inc Auxiliary PHP5 class @endlink
26 * - @link print_pdf.class_php4.inc Auxiliary PHP4 class @endlink
27 * - @link print_pdf.install (Un)Install routines @endlink
28 */
29
30 /**
31 * @file
32 * Displays Printer-friendly versions of Drupal pages.
33 *
34 * This is the core module of the PF package, with the Drupal hooks
35 * and other administrative functions.
36 *
37 * @ingroup print
38 */
39
40 define('PRINT_PATH', 'print');
41
42 define('PRINT_HTML_FORMAT', 'html');
43
44 define('PRINT_LOGO_OPTIONS_DEFAULT', 1);
45 define('PRINT_LOGO_URL_DEFAULT', '');
46 define('PRINT_FOOTER_OPTIONS_DEFAULT', 1);
47 define('PRINT_FOOTER_USER_DEFAULT', '');
48 define('PRINT_CSS_DEFAULT', '');
49 define('PRINT_URLS_DEFAULT', 1);
50 define('PRINT_COMMENTS_DEFAULT', 0);
51 define('PRINT_NEWWINDOW_DEFAULT', 1);
52
53 define('PRINT_HTML_LINK_POS_DEFAULT', 'link');
54 define('PRINT_HTML_SHOW_LINK_DEFAULT', 1);
55 define('PRINT_HTML_NODE_LINK_VISIBILITY_DEFAULT', 0);
56 define('PRINT_HTML_NODE_LINK_PAGES_DEFAULT', '');
57 define('PRINT_HTML_LINK_CLASS_DEFAULT', 'print-page');
58 define('PRINT_HTML_SYS_LINK_VISIBILITY_DEFAULT', 1);
59 define('PRINT_HTML_SYS_LINK_PAGES_DEFAULT', '');
60 define('PRINT_HTML_LINK_USE_ALIAS_DEFAULT', 0);
61 define('PRINT_HTML_BOOK_LINK_DEFAULT', 1);
62 define('PRINT_HTML_NEW_WINDOW_DEFAULT', 0);
63 define('PRINT_HTML_SENDTOPRINTER_DEFAULT', 0);
64
65 define('PRINT_SOURCEURL_ENABLED_DEFAULT', 1);
66 define('PRINT_SOURCEURL_DATE_DEFAULT', 0);
67 define('PRINT_SOURCEURL_FORCENODE_DEFAULT', 0);
68
69 define('PRINT_ROBOTS_NOINDEX_DEFAULT', 1);
70 define('PRINT_ROBOTS_NOFOLLOW_DEFAULT', 1);
71 define('PRINT_ROBOTS_NOARCHIVE_DEFAULT', 0);
72
73 define('PRINT_TYPE_SHOW_LINK_DEFAULT', 1);
74 define('PRINT_TYPE_COMMENT_LINK_DEFAULT', 0);
75 define('PRINT_TYPE_URLLIST_DEFAULT', 1);
76
77 define('PRINT_ALLOW_NORMAL_LINK', 1);
78 define('PRINT_ALLOW_BOOK_LINK', 2);
79 define('PRINT_TYPE_FIELDS_WEIGHT', 30);
80
81 /**
82 * Implementation of hook_perm().
83 */
84 function print_perm() {
85 return array('access print', 'administer print', 'node-specific print configuration', 'use PHP for link visibility');
86 }
87
88 /**
89 * Implementation of hook_theme().
90 */
91 function print_theme() {
92 return array(
93 'print_format_link' => array(
94 'arguments' => array(),
95 ),
96 );
97 }
98
99 /**
100 * Implementation of hook_menu().
101 */
102 function print_menu() {
103 $items = array();
104
105 $items[PRINT_PATH] = array(
106 'title' => 'Printer-friendly',
107 'page callback' => 'print_controller_html',
108 'access arguments' => array('access print'),
109 'type' => MENU_CALLBACK,
110 'file' => 'print.pages.inc',
111 );
112 $items[PRINT_PATH .'/'. PRINT_PATH] = array(
113 'page callback' => 'drupal_access_denied',
114 );
115 $items['admin/settings/print'] = array(
116 'title' => 'Printer, e-mail and PDF versions',
117 'description' => 'Adds a printer-friendly version link to content and administrative pages.',
118 'page callback' => 'drupal_get_form',
119 'page arguments' => array('print_html_settings'),
120 'access arguments' => array('administer print'),
121 'file' => 'print.admin.inc',
122 );
123 $items['admin/settings/print/html'] = array(
124 'title' => 'Web page',
125 'weight' => 1,
126 'type' => MENU_DEFAULT_LOCAL_TASK,
127 );
128 $items['admin/settings/print/html/options'] = array(
129 'title' => 'Options',
130 'weight' => 1,
131 'type' => MENU_DEFAULT_LOCAL_TASK,
132 );
133 $items['admin/settings/print/html/strings'] = array(
134 'title' => 'Text strings',
135 'page callback' => 'drupal_get_form',
136 'page arguments' => array('print_html_strings_settings'),
137 'access arguments' => array('administer print'),
138 'weight' => 2,
139 'type' => MENU_LOCAL_TASK,
140 'file' => 'print.admin.inc',
141 );
142 $items['admin/settings/print/common'] = array(
143 'title' => 'Settings',
144 'page callback' => 'drupal_get_form',
145 'page arguments' => array('print_main_settings'),
146 'access arguments' => array('administer print'),
147 'weight' => 10,
148 'type' => MENU_LOCAL_TASK,
149 'file' => 'print.admin.inc',
150 );
151 $items['admin/settings/print/common/options'] = array(
152 'title' => 'Options',
153 'weight' => 1,
154 'type' => MENU_DEFAULT_LOCAL_TASK,
155 );
156 $items['admin/settings/print/common/strings'] = array(
157 'title' => 'Text strings',
158 'page callback' => 'drupal_get_form',
159 'page arguments' => array('print_main_strings_settings'),
160 'access arguments' => array('administer print'),
161 'weight' => 2,
162 'type' => MENU_LOCAL_TASK,
163 'file' => 'print.admin.inc',
164 );
165
166 return $items;
167 }
168
169 /**
170 * Implementation of hook_block().
171 */
172 function print_block($op = 'list', $delta = 0, $edit = array()) {
173 switch ($op) {
174 case 'list':
175 $block[0]['info'] = t('Printer, e-mail and PDF versions');
176 $block[1]['info'] = t('Most printed');
177 return $block;
178 break;
179 case 'configure':
180 return '';
181 case 'save':
182 return;
183 case 'view':
184 switch ($delta) {
185 case 0:
186 $nid = preg_replace('!^node/!', '', $_GET['q']);
187 if (is_numeric($nid)) {
188 $node = node_load($nid);
189 }
190 else {
191 $node = NULL;
192 }
193 $funcs = get_defined_functions();
194 $block['content'] = '';
195 foreach ($funcs['user'] as $func) {
196 if (preg_match('!^print.*?_insert_link$!', $func)) {
197 $link = $func(NULL, $node);
198 if (!empty($link)) {
199 $block['content'] .= $link;
200 }
201 }
202 }
203 break;
204 case 1:
205 $block['subject'] = t('Most printed');
206 $result = db_query_range("SELECT path FROM {print_page_counter} ORDER BY totalcount DESC", 0, 3);
207 if (db_affected_rows()) {
208 $block['content'] = '<div class="item-list"><ul>';
209 while ($obj = db_fetch_object($result)) {
210 $block['content'] .= '<li>'. l(_print_get_title($obj->path), $obj->path) .'</li>';
211 }
212 $block['content'] .= '</ul></div>';
213 }
214 break;
215 }
216 return $block;
217 break;
218 }
219 }
220
221 /**
222 * Implementation of hook_link().
223 */
224 function print_link($type, $node = NULL, $teaser = FALSE) {
225 $print_html_link_pos = variable_get('print_html_link_pos', array(PRINT_HTML_LINK_POS_DEFAULT => PRINT_HTML_LINK_POS_DEFAULT));
226 $print_html_link_use_alias = variable_get('print_html_link_use_alias', PRINT_HTML_LINK_USE_ALIAS_DEFAULT);
227 $allowed_type = print_link_allowed(array('type' => $type, 'node' => $node, 'teaser' => $teaser));
228 if (($allowed_type === PRINT_ALLOW_NORMAL_LINK) && !isset($node->book) && !empty($print_html_link_pos['link'])) {
229 drupal_add_css(drupal_get_path('module', 'print') .'/css/printlinks.css');
230 $links = array();
231 $format = theme('print_format_link');
232
233 $query_arr = $_GET;
234 if ($type == 'comment') {
235 $query_arr['comment'] = $node->cid;
236 }
237 $query = print_query_string_encode($query_arr, array('q'));
238 if (empty($query)) $query = NULL;
239
240 if ($print_html_link_use_alias) {
241 $path = drupal_get_path_alias('node/'. $node->nid);
242 }
243 else {
244 $path = $node->nid;
245 }
246
247 $links['print_html'] = array(
248 'href' => PRINT_PATH .'/'. $path,
249 'title' => $format['text'],
250 'attributes' => $format['attributes'],
251 'html' => $format['html'],
252 'query' => $query,
253 );
254
255 return $links;
256 }
257 else {
258 return;
259 }
260 }
261
262 /**
263 * Implementation of hook_link_alter().
264 */
265 function print_link_alter(&$links, $node) {
266 foreach ($links as $module => $link) {
267 if (strpos($module, 'book_printer') !== FALSE) {
268 $print_html_book_link = variable_get('print_html_book_link', PRINT_HTML_BOOK_LINK_DEFAULT);
269
270 if ($print_html_book_link) {
271 $print_html_link_pos = variable_get('print_html_link_pos', array(PRINT_HTML_LINK_POS_DEFAULT => PRINT_HTML_LINK_POS_DEFAULT));
272
273 if (!empty($print_html_link_pos['link'])) {
274 $format = theme('print_format_link');
275
276 switch ($print_html_book_link) {
277 case 1:
278 $path = $link['href'];
279 break;
280 case 2:
281 $print_html_link_use_alias = variable_get('print_html_link_use_alias', PRINT_HTML_LINK_USE_ALIAS_DEFAULT);
282 $path = ($print_html_link_use_alias && isset($node->path)) ? $node->path : $node->nid;
283 break;
284 }
285
286 $links[$module] = array(
287 'href' => PRINT_PATH .'/'. $path,
288 'title' => $format['text'],
289 'attributes' => $format['attributes'],
290 'html' => $format['html'],
291 );
292 }
293 else {
294 unset($links[$module]);
295 }
296 }
297 }
298 }
299 }
300
301 /**
302 * Implementation of hook_help().
303 */
304 function print_help($path, $arg) {
305 switch ($path) {
306 case 'admin/help#print':
307 // Return a line-break version of the module README
308 return filter_filter('process', 1, NULL, file_get_contents(drupal_get_path('module', 'print') .'/README.txt') );
309 }
310
311 $print_html_link_pos = variable_get('print_html_link_pos', array(PRINT_HTML_LINK_POS_DEFAULT => PRINT_HTML_LINK_POS_DEFAULT));
312 if (($path !== 'node/%') && !(empty($print_html_link_pos['link']) && empty($print_html_link_pos['corner']))) {
313 static $output = FALSE;
314
315 if ($output === FALSE) {
316 $output = TRUE;
317
318 $link = print_insert_link();
319 if ($link) {
320 return "<span class='print-syslink'>$link</span>";
321 }
322 }
323 }
324 }
325
326 /**
327 * Implementation of hook_nodeapi().
328 */
329 function print_nodeapi(&$node, $op = 'view', $teaser, $page) {
330 switch ($op) {
331 case 'view':
332 // Insert content corner links
333 if (($teaser === FALSE) && isset($node->build_mode) && ($node->build_mode == NODE_BUILD_NORMAL)) {
334 $node->content['print_links'] = array(
335 '#value' => "<span class='print-link'></span>",
336 '#weight' => -101,
337 );
338 $print_html_link_pos = variable_get('print_html_link_pos', array(PRINT_HTML_LINK_POS_DEFAULT => PRINT_HTML_LINK_POS_DEFAULT));
339 if (!empty($print_html_link_pos['corner'])) {
340 $link = print_insert_link(NULL, $node);
341 if ($link) {
342 $node->content['print_links']['#value'] = preg_replace('!</span>$!', $link .'</span>', $node->content['print_links']['#value']);
343 }
344 }
345 }
346 break;
347 case 'load':
348 _print_set_node_fields($node);
349 break;
350 case 'update':
351 if (user_access('administer print') || user_access('node-specific print configuration')) {
352 _print_node_conf_modify($node->nid, $node->print_display, $node->print_display_comment, $node->print_display_urllist);
353 }
354 break;
355 case 'delete':
356 db_query("DELETE FROM {print_node_conf} WHERE nid = %d", $node->nid);
357 db_query("DELETE FROM {print_page_counter} WHERE path = 'node/%d'", $node->nid);
358 break;
359 }
360 }
361
362 /**
363 * Implementation of hook_form_alter().
364 */
365 function print_form_alter(&$form, $form_state, $form_id) {
366 // Add the node-type settings option to activate the printer-friendly version link
367 if ((user_access('administer print') || user_access('node-specific print configuration')) && (($form_id == 'node_type_form') ||
368 (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id))) {
369 $form['print'] = array(
370 '#type' => 'fieldset',
371 '#title' => t('Printer, e-mail and PDF versions'),
372 '#collapsible' => TRUE,
373 '#collapsed' => TRUE,
374 '#weight' => (function_exists('content_extra_field_weight') && isset($form['type'])) ? content_extra_field_weight($form['type']['#value'], 'print') : PRINT_TYPE_FIELDS_WEIGHT,
375 );
376
377 $form['print']['label'] = array(
378 '#type' => 'markup',
379 '#value' => '<p><strong>'. t('Printer-friendly version') .'</strong></p>',
380 );
381
382 $form['print']['print_display'] = array(
383 '#type' => 'checkbox',
384 '#title' => t('Show link'),
385 );
386 $form['print']['print_display_comment'] = array(
387 '#type' => 'checkbox',
388 '#title' => t('Show link in individual comments'),
389 );
390 $form['print']['print_display_urllist'] = array(
391 '#type' => 'checkbox',
392 '#title' => t('Show Printer-friendly URLs list'),
393 );
394
395 if ($form_id == 'node_type_form') {
396 $form['print']['print_display']['#default_value'] = variable_get('print_display_'. $form['#node_type']->type, PRINT_TYPE_SHOW_LINK_DEFAULT);
397 $form['print']['print_display_comment']['#default_value'] = variable_get('print_display_comment_'. $form['#node_type']->type, PRINT_TYPE_COMMENT_LINK_DEFAULT);
398 $form['print']['print_display_urllist']['#default_value'] = variable_get('print_display_urllist_'. $form['#node_type']->type, PRINT_TYPE_URLLIST_DEFAULT);
399 $form['print']['label']['#value'] = '<p><em>'. t('The settings below only apply when some of the corresponding module-wide link settings are enabled.') .'</em></p>'. $form['print']['label']['#value'];
400 }
401 else {
402 $node = $form['#node'];
403 $form['print']['print_display']['#default_value'] = isset($node->print_display) ? $node->print_display : PRINT_TYPE_SHOW_LINK_DEFAULT;
404 $form['print']['print_display_comment']['#default_value'] = isset($node->print_display_comment) ? $node->print_display_comment : PRINT_TYPE_COMMENT_LINK_DEFAULT;
405 $form['print']['print_display_urllist']['#default_value'] = isset($node->print_display_urllist) ? $node->print_display_urllist : PRINT_TYPE_URLLIST_DEFAULT;
406 $form['print']['label']['#value'] = '<p><em>'. t('The settings below only apply in case the corresponding type-specific setting is also enabled (except for the "Show link in individual comments").') .'</em></p>'. $form['print']['label']['#value'];
407 }
408 }
409 }
410
411 /**
412 * Implementation of hook_content_extra_fields().
413 */
414 function print_content_extra_fields($type_name) {
415 $fields['print'] = array(
416 'label' => t('Printer, e-mail and PDF versions'),
417 'description' => t('Print module form.'),
418 'weight' => PRINT_TYPE_FIELDS_WEIGHT,
419 );
420 return $fields;
421 }
422
423 /**
424 * Implementation of hook_content_build_modes().
425 */
426 function print_content_build_modes() {
427 return array(
428 'print' => array(
429 'title' => t('Print'),
430 'build modes' => array(
431 NODE_BUILD_PRINT => array(
432 'title' => t('Print'),
433 'views style' => TRUE,
434 ),
435 ),
436 ),
437 );
438 }
439
440 /**
441 * Auxiliary function to assign the per-node settings to the node object fields
442 *
443 * @param $node
444 * node to be modified
445 */
446 function _print_set_node_fields(&$node) {
447 if (isset($node->nid)) {
448 $res = db_fetch_object(db_query("SELECT link, comments, url_list FROM {print_node_conf} WHERE nid = %d", $node->nid));
449 }
450 else {
451 $res = FALSE;
452 }
453 $node->print_display = $res ? intval($res->link) : PRINT_TYPE_SHOW_LINK_DEFAULT;
454 $node->print_display_comment = $res ? intval($res->comments) : PRINT_TYPE_COMMENT_LINK_DEFAULT;
455 $node->print_display_urllist = $res ? intval($res->url_list) : PRINT_TYPE_URLLIST_DEFAULT;
456 }
457
458 /**
459 * Auxiliary function to discover a given page's title
460 *
461 * @param $path
462 * path of the page being identified
463 * @return
464 * string with the page's title
465 */
466 function _print_get_title($path) {
467 $path = drupal_get_normal_path($path);
468 $nid = preg_replace('!^node/!', '', $path);
469 if (is_numeric($nid)) {
470 $res = db_fetch_object(db_query("SELECT title FROM {node} WHERE nid = %d", $nid));
471 return $res->title;
472 }
473 else {
474 $res = db_fetch_object(db_query("SELECT link_title FROM {menu_links} WHERE link_path = '%s'", $path));
475 return $res->link_title;
476 }
477 }
478
479 /**
480 * Update the print_node_conf table to reflect the given attributes
481 * If updating to the default values, delete the record.
482 *
483 * @param $nid
484 * value of the nid field (primary key)
485 * @param $link
486 * value of the link field (0 or 1)
487 * @param $comments
488 * value of the comments field (0 or 1)
489 * @param $url_list
490 * value of the url_list field (0 or 1)
491 */
492 function _print_node_conf_modify($nid, $link, $comments, $url_list) {
493 if (($link == PRINT_TYPE_SHOW_LINK_DEFAULT) && ($comments == PRINT_TYPE_COMMENT_LINK_DEFAULT) &&
494 ($url_list == PRINT_TYPE_URLLIST_DEFAULT)) {
495 db_query("DELETE FROM {print_node_conf} WHERE nid = %d", $nid);
496 }
497 else {
498 db_query("UPDATE {print_node_conf} SET link = %d, comments = %d, url_list = %d WHERE nid = %d", $link, $comments, $url_list, $nid);
499 if (!db_affected_rows()) {
500 db_query("INSERT INTO {print_node_conf} (nid, link, comments, url_list) VALUES (%d, %d, %d, %d)", $nid, $link, $comments, $url_list);
501 }
502 }
503 }
504
505 /**
506 * Auxiliary function to fill the Printer-friendly link attributes
507 *
508 * @param $title
509 * text to displayed by the link when hovering over it with the mouse
510 * @param $class
511 * class attribute to be used in the link
512 * @param $new_window
513 * if TRUE opens the target page in a new window
514 * @return
515 * array of formatted attributes
516 */
517 function print_fill_attributes($title = '', $class = '', $new_window = FALSE) {
518 $print_newwindow = variable_get('print_newwindow', PRINT_NEWWINDOW_DEFAULT);
519 $print_robots_noindex = variable_get('print_robots_noindex', PRINT_ROBOTS_NOINDEX_DEFAULT);
520
521 $attributes = array();
522 $attributes['title'] = $title;
523 if (!empty($class)) {
524 $attributes['class'] = $class;
525 }
526
527 if ($new_window) {
528 switch ($print_newwindow) {
529 case 0:
530 $attributes['target'] = '_blank';
531 break;
532 case 1:
533 $attributes['onclick'] = 'window.open(this.href); return false';
534 break;
535 }
536 }
537 if (!empty($print_robots_noindex)) {
538 $attributes['rel'] = 'nofollow';
539 }
540 return $attributes;
541 }
542
543 /**
544 * Auxiliary function to set the link text and html flag
545 *
546 * @param $type
547 * type of link: 0 or 1 for a text-only link, 2 for icon-only and 3 for
548 * both text and icon
549 * @param $text
550 * text to be displayed on the link to the printer-friendly page
551 * @param $img
552 * path to the icon file
553 * @return
554 * array with the link text and html flag
555 */
556 function _print_format_link_aux($type = 0, $text = '', $img = '') {
557 if ($type >= 2) {
558 $html = TRUE;
559 switch ($type) {
560 case 2:
561 $text = theme('image', $img, $text, $text, array('class' => 'print-icon'));
562 break;
563 case 3:
564 $text = theme('image', $img, $text, $text, array('class' => 'print-icon print-icon-margin')) . $text;
565 break;
566 }
567 }
568 else {
569 $html = FALSE;
570 }
571
572 return array('text' => $text,
573 'html' => $html,
574 );
575 }
576
577 /**
578 * Format the Printer-friendly link
579 *
580 * @return
581 * array of formatted attributes
582 * @ingroup themeable
583 */
584 function theme_print_format_link() {
585 $print_html_link_class = variable_get('print_html_link_class', PRINT_HTML_LINK_CLASS_DEFAULT);
586 $print_html_new_window = variable_get('print_html_new_window', PRINT_HTML_NEW_WINDOW_DEFAULT);
587 $print_html_show_link = variable_get('print_html_show_link', PRINT_HTML_SHOW_LINK_DEFAULT);
588 $print_html_link_text = filter_xss(variable_get('print_html_link_text', t('Printer-friendly version')));
589
590 $img = drupal_get_path('module', 'print') .'/icons/print_icon.gif';
591 $title = t('Display a printer-friendly version of this page.');
592 $class = strip_tags($print_html_link_class);
593 $new_window = $print_html_new_window;
594 $format = _print_format_link_aux($print_html_show_link, $print_html_link_text, $img);
595
596 return array('text' => $format['text'],
597 'html' => $format['html'],
598 'attributes' => print_fill_attributes($title, $class, $new_window),
599 );
600 }
601
602 /**
603 * Auxiliary function to display a formatted Printer-friendly link
604 *
605 * Function made available so that developers may call this function from
606 * their defined pages/blocks.
607 *
608 * @param $path
609 * path of the original page (optional). If not specified, the current URL
610 * is used
611 * @param $node
612 * an optional node object, to be used in defining the path, if used, the
613 * path argument is irrelevant
614 * @return
615 * string with the HTML link to the printer-friendly page
616 */
617 function print_insert_link($path = NULL, $node = NULL) {
618 if ($node !== NULL) {
619 $nid = $node->nid;
620 $path = 'node/'. $nid;
621 $allowed_type = print_link_allowed(array('node' => $node));
622 }
623 else {
624 if ($path === NULL) {
625 $nid = preg_replace('!^node/!', '', $_GET['q']);
626 $path = $_GET['q'];
627 }
628 else {
629 $nid = NULL;
630 }
631 $allowed_type = print_link_allowed(array('path' => $path));
632 }
633
634 if ($allowed_type) {
635 if ($nid !== NULL) {
636 if ($allowed_type === PRINT_ALLOW_BOOK_LINK) {
637 $path = 'book/export/html/'. $nid;
638 }
639 else {
640 if (variable_get('print_html_link_use_alias', PRINT_HTML_LINK_USE_ALIAS_DEFAULT)) {
641 $path = drupal_get_path_alias($path);
642 }
643 else {
644 $path = $nid;
645 }
646 }
647 $path = PRINT_PATH .'/'. $path;
648 $query = print_query_string_encode($_GET, array('q'));
649 if (empty($query)) {
650 $query = NULL;
651 }
652 }
653 else {
654 $query = NULL;
655 }
656 drupal_add_css(drupal_get_path('module', 'print') .'/css/printlinks.css');
657 $format = theme('print_format_link');
658 return '<span class="print_html">'. l($format['text'], $path, array('attributes' => $format['attributes'], 'query' => $query, 'absolute' => TRUE, 'html' => $format['html'])) .'</span>';
659 }
660 else {
661 return FALSE;
662 }
663 }
664
665 /**
666 * Determine if the current page is enabled according to the visibility settings
667 *
668 * @param $visibility
669 * current visibility settings:
670 * 0 for show on every page except the listed pages
671 * 1 for show on only the listed pages
672 * @param $pages
673 * list of pages
674 * @return
675 * TRUE if it is enabled, FALSE otherwise
676 */
677 function _print_page_match($visibility, $pages) {
678 if ($pages) {
679 if ($visibility == 2) {
680 return drupal_eval($pages);
681 }
682 $path = drupal_get_path_alias($_GET['q']);
683 $page_match = drupal_match_path($path, $pages);
684 if ($path != $_GET['q']) {
685 $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
686 }
687
688 return !($visibility xor $page_match);
689 }
690 else {
691 return !$visibility;
692 }
693 }
694
695 /**
696 * Determine a the link to the PF version is allowed depending on all possible settings
697 *
698 * @param $args
699 * array containing the possible parameters:
700 * teaser, node, type, path
701 * @return
702 * FALSE if not allowed
703 * PRINT_ALLOW_NORMAL_LINK if a normal link is allowed
704 * PRINT_ALLOW_BOOK_LINK if a link is allowed in a book node
705 */
706 function print_link_allowed($args) {
707 if (!empty($args['teaser']) || !user_access('access print')) {
708 // If showing only the teaser or the user is not allowed or link is disabled
709 return FALSE;
710 }
711 if (!empty($args['path'])) {
712 $nid = preg_replace('!^node/!', '', drupal_get_normal_path($args['path']));
713 if (is_numeric($nid)) {
714 $args['node'] = node_load($nid);
715 }
716 }
717 if (!empty($args['node'])) {
718 static $node_type = '';
719
720 $node = $args['node'];
721 if (isset($node->type)) {
722 $node_type = $node->type;
723 }
724 // Node
725 $print_html_node_link_visibility = variable_get('print_html_node_link_visibility', PRINT_HTML_NODE_LINK_VISIBILITY_DEFAULT);
726 $print_html_node_link_pages = variable_get('print_html_node_link_pages', PRINT_HTML_NODE_LINK_PAGES_DEFAULT);
727
728 if (!_print_page_match($print_html_node_link_visibility, $print_html_node_link_pages)) {
729 // Page not in visibility list
730 return FALSE;
731 }
732 elseif (isset($args['type']) && ($args['type'] == 'comment') && isset($node_type)) {
733 // Link is for a comment, return the configured setting
734 $res = db_fetch_object(db_query("SELECT comments FROM {print_node_conf} WHERE nid = %d", $node->nid));
735 $print_display_comment = $res ? intval($res->comments) : PRINT_TYPE_COMMENT_LINK_DEFAULT;
736 if (($print_display_comment) ||
737 variable_get('print_display_comment_'. $node_type, PRINT_TYPE_COMMENT_LINK_DEFAULT)) {
738 return PRINT_ALLOW_NORMAL_LINK;
739 }
740 }
741 else {
742 // Node link
743 if ((!$node->print_display) || (isset($node_type) &&
744 !variable_get('print_display_'. $node_type, PRINT_TYPE_SHOW_LINK_DEFAULT))) {
745 // Link for this node type is disabled
746 return FALSE;
747 }
748 elseif (isset($node->book)) {
749 // Node is a book;
750 $print_html_book_link = variable_get('print_html_book_link', PRINT_HTML_BOOK_LINK_DEFAULT);
751 switch ($print_html_book_link) {
752 case 1:
753 if (user_access('access printer-friendly version')) {
754 return PRINT_ALLOW_BOOK_LINK;
755 }
756 break;
757 case 2:
758 return PRINT_ALLOW_NORMAL_LINK;
759 }
760 }
761 else {
762 return PRINT_ALLOW_NORMAL_LINK;
763 }
764 }
765 }
766 else {
767 // 'System' page
768 $print_html_sys_link_visibility = variable_get('print_html_sys_link_visibility', PRINT_HTML_SYS_LINK_VISIBILITY_DEFAULT);
769 $print_html_sys_link_pages = variable_get('print_html_sys_link_pages', PRINT_HTML_SYS_LINK_PAGES_DEFAULT);
770
771 return _print_page_match($print_html_sys_link_visibility, $print_html_sys_link_pages);
772 }
773 return FALSE;
774 }
775
776 /**
777 * Parse an array into a valid urlencoded query string.
778 * Modified from drupal_query_string_encode to prevent re-encoding of
779 * encoded original.
780 *
781 * @param $query
782 * The array to be processed e.g. $_GET
783 * @param $exclude
784 * The array filled with keys to be excluded.
785 * @return
786 * urlencoded string which can be appended to/as the URL query string
787 */
788 function print_query_string_encode($query, $exclude = array(), $parent = '') {
789 $params = array();
790 foreach ($query as $key => $value) {
791 if ($parent) {
792 $key = $parent .'['. $key .']';
793 }
794
795 if (in_array($key, $exclude)) {
796 continue;
797 }
798
799 if (is_array($value)) {
800 $params[] = print_query_string_encode($value, $exclude, $key);
801 }
802 else {
803 $params[] = $key .'='. rawurlencode($value);
804 }
805 }
806
807 return implode('&', $params);
808 }