<?php
/*
Plugin Name: WordPress AutoLink
Plugin URI: http://rudd-o.com/projects/wp-autolink/
Description: Break free from linkrot and complicated URLs in your posts and pages — <a href="http://rudd-o.com/projects/wp-autolink/wp-autolink-usage/">Usage instructions</a>
Version: 0.5.2
Author: Manuel Amador (Rudd-O)
Author URI: http://rudd-o.com/
*/

/*  Copyright 2005,2006  Manuel Amador

Derivative work from bsuite, written by Casey Bisson

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

require_once(dirname(__FILE__)."/tagmogrify/tagmogrify.php");

/* start defines */

$autolink_recognized_html_attributes = array("href","src","cite");
$autolink_recognized_js_attributes = array("onclick","onfocus","onblur","onmouseover","onmouseout","onchange","ondblclick");

/* end defines */

/* start debugging helpers */

function autolink_report_log($message) {
	return; /* turned off for normal work */
	trigger_error($message,E_USER_NOTICE);
}

/* end debugging helpers */


/* the code for displaying warnings to the user in the post editor */
/* this code is shared with autolink but namespaced to prevent clashes */

$autolink_warnings = "";
$autolink_warnings_displayed = false;

function autolink_warning_footer() { global $autolink_warnings; echo $autolink_warnings; }
/* position_id is the HTML id of the element after which we want to place this warning */
function autolink_display_warning($warning_id,$position_id,$title,$contents) {
	global $autolink_warnings;
	$autolink_warnings .= "
	<div id='$warning_id' class='updated fade-ff0000'><p><strong>".$title.".</strong> ".$contents."</p></div>
	";
	$autolink_warnings .= '<script language="javascript" type="text/javascript">';
	$autolink_warnings .= "var thewarning = document.getElementById('$warning_id');";
	$autolink_warnings .= "var theelement = document.getElementById('$position_id');";
	$autolink_warnings .= "if (theelement) { if (theelement.nextSibling) { theelement.parentNode.insertBefore(thewarning,theelement.nextSibling); } else { theelement.parentNode.appendChild(thewarning); } }";
	$autolink_warnings .= '</script>';

	global $autolink_warnings_displayed;
	if (!$autolink_warnings_displayed) {
		add_action('admin_footer', 'autolink_warning_footer');
		$autolink_warnings_displayed = true;
	}
}

/* end admin communication code */

/* start utility functions */

/* I UNDERSTAND what's the purpose of this function.  I just don't understand why you guys (WP devels) NEEDED to place the content_edit_pre filter *after* this piece of shit code.  content_edit_pre is useless for this very reason.  */

function autolink_unhtmlspecialchars ($content) {
	$trans = get_html_translation_table(HTML_SPECIALCHARS);
	$trans = array_flip($trans);
	return strtr($content, $trans);
}

function autolink_undo_format_to_edit_shitload($content) {
	$richedit = ( 'true' == get_user_option('rich_editing') ) ? true : false;
	if (! $richedit ) $content = autolink_unhtmlspecialchars($content);
	return $content;
} function autolink_uftes($content) { return autolink_undo_format_to_edit_shitload($content); }

function autolink_redo_format_to_edit_shitload($content) {
	$richedit = ( 'true' == get_user_option('rich_editing') ) ? true : false;
	if (! $richedit ) $content = htmlspecialchars($content);
	return $content;
} function autolink_rftes($content) { return autolink_redo_format_to_edit_shitload($content); }

function autolink_get_post_permalink($handle) {

	global $wpdb;

	if (intval($handle)."" === $handle) { /* we have a numeric post link */
		$sql = "SELECT ID FROM $wpdb->posts WHERE ID=$handle limit 1;";
	} else { /* we have a text post link */
		$handle = $wpdb->escape($handle);
		$sql = "SELECT ID FROM $wpdb->posts WHERE post_name='$handle' limit 1;";
	}
	/* to verify its existence in the database */
	$post_id = $wpdb->get_var( $sql );
	if ($post_id) {
		return array($post_id,get_permalink($post_id));
	}

}

function alunrelativize($path) {
	/* returns a path where ./ and ../ have been resolved, with no trailing slashes
	if the path begins with ../, it leaves those alone
	*/
	$components = explode("/",$path);
	$newcomponents = array();
	$validelementsfound = false;
	for ($i = 0; $i < sizeof($components); $i++) {
		if ($components[$i] != ".." && $components[$i] != "") $validelementsfound = true;
		if (!$validelementsfound) {
			if ($components[$i] == ".") {}
			else $newcomponents[] = $components[$i];
		}
		else {
			if ($components[$i] == "..") array_pop($newcomponents);
			elseif ($components[$i] == ".") {}
			else { $newcomponents[] = $components[$i]; }
		}
	}
	while ($newcomponents[sizeof($newcomponents)-1] == "") array_pop($newcomponents);
	$path = implode("/",$newcomponents);
	return $path;
}

/* we need to deprecate content: in favor of blog: and uploads: so users can know */
function autolink_get_content_url($handle,$minusslash=false) {

	$dum = wp_upload_dir();
	if ($dum["error"]) $baseurl = get_settings("siteurl") . "/wp-content/uploads";
	else {
		$baseurl = $dum["url"];
		if (get_settings('uploads_use_yearmonth_folders')) {
			$baseurl = trailingslashit($baseurl) . "../../";
		}
		$baseurl = alunrelativize($baseurl);
	}
	if (!$handle && $minusslash) { return $baseurl; }
	return $baseurl . "/" . $handle;

}

function autolink_get_weblog_url($handle,$minusslash=false) {

	if (!$handle && $minusslash) { return get_settings("siteurl"); }
	return get_settings("siteurl") . "/" . $handle;

}

function autolink_refers_to_this_weblog($url) {
	$weblog_url = autolink_get_weblog_url("");
	if (substr($url,0,strlen($weblog_url)) == $weblog_url) return true;

	$splits = @parse_url($url);
	$splits2 = @parse_url($weblog_url);
	foreach (array("scheme","host","port","user","pass") as $component) {
		// equalize in case the supplied url by the user was a partial url
		if (!array_key_exists($component,$splits)) $splits[$component] = null;
		if (!array_key_exists($component,$splits2)) $splits2[$component] = null;
		if (!$splits[$component]) $splits[$component] = $splits2[$component];
		if ($splits[$component] != $splits2[$component]) return false;
	}
	if (!array_key_exists("path",$splits)) $splits["path"] = null; /* eat shit, dumb warnings! */
	if (!array_key_exists("path",$splits2)) $splits2["path"] = null;
	$weblog_path = $splits2["path"];
	$url_path = $splits["path"];
	if (substr($url_path,0,strlen($weblog_path)) == $weblog_path) return true;
	return false;
}

function autolink_id_to_slug($postid) {
	global $wpdb;
	$sql = "SELECT post_name FROM $wpdb->posts WHERE ID=$postid limit 1;";
	/* to verify its existence in the database */
	$slug = $wpdb->get_var( $sql );
	if ($slug) return $slug;
	return $postid;
}

function autolink_swallow_errors($id,$msg) { return; }

function autolink_get_post_shortcut_from_permalink($querystring) {
	$post_shortcut = null;
	set_error_handler("autolink_swallow_errors");
	$postid = url_to_postid($querystring);
	restore_error_handler();
	if ($postid) {
		$s = autolink_id_to_slug($postid);
		if ($s) $post_shortcut = "post:$s";
	}
	return $post_shortcut;
}

$autolink_entity_manifest = file_get_contents(dirname(__FILE__)."/entity-manifest.txt");
$autolink_entity_manifest = preg_replace("/<!--.+?-->/s","",$autolink_entity_manifest);
$autolink_entity_manifest = preg_replace("/ --.+?--/s","",$autolink_entity_manifest);
$autolink_entity_manifest = '<!DOCTYPE chapter SYSTEM "/just/a/test.dtd" [' . "\n" . $autolink_entity_manifest . "]>\n";

function autolink_simple_mogrifier_factory($function_name,$mogrificator_type) {
	global $autolink_entity_manifest;
	$mogrificator_type = "add_{$mogrificator_type}_mogrificator";
	$m = new TagMogrifier(get_settings('blog_charset'),$fatal_errors=false,$entity_declarations=$autolink_entity_manifest);
	$m->$mogrificator_type($function_name);
	return $m;
}

/* end utility functions */

/* start rendering routines post:, content: -> http://... */

function autolink_render_html_post_links(&$attribute,$titles=true) {

	$attrvalue = $attribute->nodeValue;

	if (substr($attrvalue,0,strlen('post:')) == "post:") {
		/* we have a post link */
		$handle = substr($attrvalue,strlen('post:'),strlen($attrvalue));
		
		$splits = explode("#",$handle,2);
		$handle = $splits[0];
		if (count($splits) == 2) { /* there WAS an anchor */ $anchor = $splits[1];}
		else { $anchor = null; }

		list($post_id,$permalink) = autolink_get_post_permalink($handle);

		if ($permalink) {
			$attrvalue = apply_filters('the_permalink', $permalink );
			if ($anchor) {
				$attrvalue .= "#" . $anchor;
			}
			$tag = $attribute->parentNode;
			if (strtolower($attribute->nodeName) == "href" && !$tag->getAttribute("title") && $titles == true) { /* we only autofill the title if it's an a href link and it already does not have a title and if titles were explicitly requested */
				$title = get_the_title($post_id);
				autolink_report_log("AutoLink render links: setting title: ".$title);
 				$tag->setAttribute("title",$title);
				$disp = $tag->getAttribute("title");
				autolink_report_log("AutoLink render links: title set: ".$disp);
			}
		}
	}

	if ($attrvalue != $attribute->nodeValue) {
		autolink_report_log("AutoLink render links: modifying: ".$attribute->nodeValue);
		$attribute->nodeValue = htmlspecialchars($attrvalue);
		autolink_report_log("AutoLink render links: new value: ".$attribute->nodeValue);
	}

}

function autolink_render_html_post_links_notitles(&$attribute) { return autolink_render_html_post_links($attribute,$titles=false); }

function autolink_render_html_content_links(&$attribute) {

	$attrvalue = $attribute->nodeValue;

	if (substr($attrvalue,0,strlen('content:')) == "content:") {
		/* we have a content link */
		$handle = substr($attrvalue,strlen('content:'),strlen($attrvalue));
		$attrvalue = autolink_get_content_url($handle);
	}

	if ($attrvalue != $attribute->nodeValue) {
		autolink_report_log("AutoLink render content links: modifying: ".$attribute->nodeValue);
		$attribute->nodeValue = htmlspecialchars($attrvalue);
		autolink_report_log("AutoLink render content links: new value: ".$attribute->nodeValue);
	}

}

function autolink_render_js_content_links(&$attribute) {

	$attrvalue = $attribute->nodeValue;

	$attrvalue = str_replace("'content:", "'" . autolink_get_content_url("") , $attrvalue);
	$attrvalue = str_replace("\"content:", "\"" . autolink_get_content_url("") , $attrvalue);
	
	if ($attrvalue != $attribute->nodeValue) {
		autolink_report_log("AutoLink render js links: modifying: ".$attribute->nodeValue);
		$attribute->nodeValue = htmlspecialchars($attrvalue);
		autolink_report_log("AutoLink render js links: new value: ".$attribute->nodeValue);
	}

}

function autolink_add_rel_lightbox(&$tag) {

	$parentnode = $tag->parentNode;
	if (strtolower($parentnode->tagName) == "a") {
		$hrefat = $parentnode->getAttribute("href");
		$relat = $parentnode->getAttribute("rel");
		if ($hrefat && !$relat) {
			$extensions = array(".bmp",".png",".gif",".jpg",".jpeg");
			$matched = false;
			foreach ($extensions as $e) {
				$linkext = strtolower(substr($hrefat, - strlen($e),strlen($e)));
				if ($linkext == $e) { $matched = true; break; }
			}
			if ($matched) {
				$parentnode->setAttribute("rel","lightbox");
				autolink_report_log("AutoLink add rel lightbox: adding rel=lightbox attribute to anchor $hrefat");
			}
		}
	}

}

function autolink_render($content,$for_editing) {

	global $autolink_recognized_html_attributes,$autolink_recognized_js_attributes;

	// html post links
	if ($for_editing) $m1 = autolink_simple_mogrifier_factory("autolink_render_html_post_links_notitles","attribute");
	else $m1 = autolink_simple_mogrifier_factory("autolink_render_html_post_links","attribute");
	foreach ($autolink_recognized_html_attributes as $attribute) {
		$m1->add_attribute_match(null,"istring:$attribute","regexp:/^post:/");
	}

	// html content links
	$m2 = autolink_simple_mogrifier_factory("autolink_render_html_content_links","attribute");
	foreach ($autolink_recognized_html_attributes as $attribute) {
		$m2->add_attribute_match(null,"istring:$attribute","regexp:/^content:/");
	}

	// js content links
	$m3 = autolink_simple_mogrifier_factory("autolink_render_js_content_links","attribute");
	foreach ($autolink_recognized_js_attributes as $attribute) {
		$m3->add_attribute_match(null,"istring:$attribute","regexp:/'content:/");
		$m3->add_attribute_match(null,"istring:$attribute","regexp:/\"content:/");
	}

	if (!$for_editing) {
		$m4 = autolink_simple_mogrifier_factory("autolink_add_rel_lightbox","tag");
		$m4->add_tag_match("istring:img",null,null);
	}

	$newcontent = $content;
	if ($for_editing) {
		if ($newcontent != false) $newcontent = $m1->run($newcontent);
		if ($newcontent != false) $newcontent = $m2->run($newcontent);
		if ($newcontent != false) $newcontent = $m3->run($newcontent);
	}
	else {
		if ($newcontent != false) $newcontent = $m1->run($newcontent);
		if ($newcontent != false) $newcontent = $m2->run($newcontent);
		if ($newcontent != false) $newcontent = $m3->run($newcontent);
		if ($newcontent != false) $newcontent = $m4->run($newcontent);
	}
	$warning = "<!-- AutoLink could not process this post because it has invalid HTML.  Please fix it. -->";
	if ($newcontent === false) {
		if ($for_editing) {
			autolink_display_warning("autolink-warning","write-post",'AutoLink cannot process this post',sprintf('This post contains invalid XML.  AutoLink cannot process posts with invalid XML.  Please fix it, and then hit %1$s.', __("Save and Continue Editing")));
		}
		return $content;
	}

	/* one-off bug fix (workaround?) for the hateful singleton tag bug in tagmogrify */
	if (!$for_editing) {
		$newcontent = autolink_unfuck_singleton_tags($newcontent);
	}

	return $newcontent;

}

function autolink_render_for_display($content) { return autolink_render($content,$for_editing=false); }
function autolink_render_for_editing($content) { return autolink_render($content,$for_editing=true); }

/* end rendering routines post:, content: -> http://... */

/* start simplification routines http://... -> content:, post: */

function autolink_simplify_html_post_links ($attribute) {

	$attrvalue = $attribute->nodeValue;
	
	if (autolink_refers_to_this_weblog($attrvalue)) { /* only if this link points to this weblog!
		/* we save the anchor */
		$splits = explode("#",$attrvalue,2);
		if (count($splits) == 1) {
			$presumed_permalink = $attrvalue;
			$anchor = null;
		} else list($presumed_permalink,$anchor) = $splits;
	
		$shortcut = autolink_get_post_shortcut_from_permalink($presumed_permalink);
		if ($shortcut) {
			$attrvalue = $shortcut;
			/* if we had an anchor, we append it to the post shortcut link */
			if ($anchor) $attrvalue .= "#" . $anchor;
	
			/* andwe finally store the node value */
			autolink_report_log("AutoLink simplify posts: modifying: ".$attribute->nodeValue);
			$attribute->nodeValue = $attrvalue;
			autolink_report_log("AutoLink simplify posts: new value: ".$attribute->nodeValue);
		}
	}

}

function autolink_simplify_html_content_links ($attribute) {

	$attrvalue = $attribute->nodeValue;

	$content_url = autolink_get_content_url("");

	if (substr($attrvalue,0,strlen($content_url)) == $content_url) {
		/* we have a content link */
		$handle = substr($attrvalue,strlen($content_url),strlen($attrvalue)); /* which should give me the rest */
		$attrvalue = "content:" . $handle;
	} elseif ($attrvalue == $content_url) {
		$attrvalue = "content:";
	}

	$content_url = autolink_get_content_url("",$minusslash=true);

	// in case they forget the trailing slash
	if ($attrvalue == $content_url) {
		$attrvalue = "content:";
	}

	if ($attrvalue != $attribute->nodeValue) {
		autolink_report_log("AutoLink simplify content links: modifying: ".$attribute->nodeValue);
		$attribute->nodeValue = htmlspecialchars($attrvalue);
		autolink_report_log("AutoLink simplify content links: new value: ".$attribute->nodeValue);
	}

}

function autolink_simplify_js_content_links(&$attribute) {

	$attrvalue = $attribute->nodeValue;

	$attrvalue = str_replace("'" . autolink_get_content_url("") , "'content:" , $attrvalue);
	$attrvalue = str_replace("\"" . autolink_get_content_url("") , "\"content:" , $attrvalue);
	// in case they forget the trailing slash
	$attrvalue = str_replace("'" . autolink_get_content_url("",$minusslash=true) . "'" , "'content:'" , $attrvalue);
	$attrvalue = str_replace("\"" . autolink_get_content_url("",$minusslash=true) . "\"" , "\"content:\"" , $attrvalue);
	
	if ($attrvalue != $attribute->nodeValue) {
		autolink_report_log("AutoLink simplify js links: modifying: ".$attribute->nodeValue);
		$attribute->nodeValue = $attrvalue;
		autolink_report_log("AutoLink simplify js links: new value: ".$attribute->nodeValue);
	}

}

function autolink_simplify($content) {

	global $autolink_recognized_html_attributes,$autolink_recognized_js_attributes;

	// html post links
	$m1 = autolink_simple_mogrifier_factory("autolink_simplify_html_post_links","attribute");
	foreach ($autolink_recognized_html_attributes as $attribute) {
		$m1->add_attribute_match(null,"istring:$attribute",null);
	}

	// html content links
	$m2 = autolink_simple_mogrifier_factory("autolink_simplify_html_content_links","attribute");
	foreach ($autolink_recognized_html_attributes as $attribute) {
		$m2->add_attribute_match(null,"istring:$attribute",null);
	}

	// js content links
	$m3 = autolink_simple_mogrifier_factory("autolink_simplify_js_content_links","attribute");
	foreach ($autolink_recognized_js_attributes as $attribute) {
		$m3->add_attribute_match(null,"istring:$attribute",null);
	}

	$newcontent = $content;
	if ($newcontent != false) $newcontent = $m1->run($newcontent);
	if ($newcontent != false) $newcontent = $m2->run($newcontent);
	if ($newcontent != false) $newcontent = $m3->run($newcontent);
	if ($newcontent === false) return $content;
	return $newcontent;

}

/* end simplification routines http://... -> content:, post: */

/* start mass operation routines */

function autolink_get_total_posts() {
	global $wpdb;
	$sql = "select COUNT(ID) from {$wpdb->posts}";
	return intval($wpdb->get_var($sql));
}

function autolink_replacecrlf($content) {
	return str_replace(chr(13) . chr(10),chr(10),$content); // replace crlf for lf only, otherwise xmllint gets anxious
}

function autolink_is_diff_available() {
	global $autolink_diff_available;
	if (!isset($autolink_diff_available)) {
		$retvalue = 0;$output = array();
		exec("diff /dev/null /dev/null",$output,$retvalue);
		if ($retvalue != 0) $autolink_diff_available = false;
		else $autolink_diff_available = true;
	}
	return $autolink_diff_available;
}

function autolink_get_diff($a,$b) {

	if (autolink_is_diff_available()) {
		$afile = tempnam("/tmp","autolink");
		$bfile = tempnam("/tmp","autolink");
		$ap = fopen($afile,"wb");
		$bp = fopen($bfile,"wb");
		fwrite($ap,$a);
		fwrite($bp,$b);
		fflush($ap);
		fflush($bp);
		fclose($ap);
		fclose($bp);
		$afile2 = escapeshellarg($afile);
		$bfile2 = escapeshellarg($bfile);
		$output = `diff -u $afile2 $bfile2`;
	
		unlink($afile);
		unlink($bfile);
	
		return $output;
	} else {
		return "diff is not available on this server";
	}
}

function autolink_mass_simplify($commit = false, $start_callback = null, $finish_callback = null, $progress_callback = null) { /* make report show diff  and warnings */
	global $wpdb;
	global $user_ID;
	get_currentuserinfo();
	$sql = "select ID,post_content from {$wpdb->posts}";
	$wpdb->query($sql);
	$report = array();
	$allcontent = array();
	$results = $wpdb->get_results();
	foreach ($results as $row) {
		if ($row->ID && user_can_edit_post($user_ID, $row->ID)) $allcontent[$row->ID] = 
			str_replace("<hr />","<hr/>",
				str_replace("<p />","</p>",
					str_replace("<br />","<br/>",autolink_replacecrlf($row->post_content))
				)
			)
			;
	}
	if ($start_callback) $start_callback(sizeof($allcontent));
	foreach ($allcontent as $key=>$val) {
		$id = $key;
		$content = $val;
		if ($progress_callback) $progress_callback($id);
		autolink_trap_errors();
		$newcontent = autolink_simplify($content);
		$messages = autolink_halt_error_trap_and_return();

		$report_entry = $id;
		$report_action = "none";
		$report_messages = autolink_format_error_report($messages);
		
		$litmus = "TagMogrify encountered invalid XML";
		$litmus2 = "Warning";

		if (strstr($report_messages,$litmus) === false && strstr($report_messages,$litmus2) === false) {
			if ($newcontent == $content) $report_action = "unchanged";
			else {
				$report_action = "autolinked";
				if (autolink_is_diff_available())
					$report_messages .= "<p>Changes (<code>diff</code> view):</p><pre>" . htmlspecialchars(autolink_get_diff($content,$newcontent)) . "</pre>";
				else
					$report_messages .= "<p>New content:</p><pre style='overflow: auto;'>" . htmlspecialchars($newcontent) . "</pre>";
				if ($commit) {
					$wpdb->query("update {$wpdb->posts} set post_content = '"
						. $wpdb->escape($newcontent) . "' where ID = $id");
				}
			}
		 } else { //found invalid xml
			$report_action = "invalidxhtml";
		}

		if ($report_action != "unchanged")
			array_push($report,array($report_entry,$report_action,$report_messages));
	}
	if ($finish_callback) $finish_callback();
	return $report;
}

function autolink_user_requested_futureproof() {
	if (array_key_exists("futureproof",$_POST) || array_key_exists("futureproofcommit",$_POST)) return true;
	return false;
}

function autolink_user_requested_futureproof_committed() {
	if (array_key_exists("futureproofcommit",$_POST)) return true;
	return false;
}

/* manage screen: progress bar functions */

$al_progress_counter = 0;
$al_total_count = 0;
$al_report_interval = 0;
$al_progress_style = "<style type='text/css'>#progress-bar-container {border: 1px solid #A3A3A3;background:#F2F2F2;}
#progress-bar {border: 1px solid #A3A3A3;background: #A3A3A3;height: 1em;}</style>";


function autolink_report_make_progress_bar() {
global $al_progress_style; print $al_progress_style;?>
<h4 style="text-align:center; margin-bottom: 0.1em; padding-bottom: 0em;"><span id="progress-status">Process initiating...</span></h4><div id="progress-bar-container"><div id="progress-bar"></div></div>
<script language="JavaScript" type="text/javascript">
function updateStatusBar(newStatusText) {
	var vsnode = document.getElementById("progress-bar");
	var style = "width: " + newStatusText + "%;";
	vsnode.setAttribute("style",style);
}
function us(progress,total,intext) {
	var vsnode = document.getElementById("progress-status");
	while (vsnode.childNodes.length > 0) vsnode.removeChild(vsnode.childNodes[0]);
	vsnode.appendChild(document.createTextNode("Processing entry " + progress + " out of " + total + " entries..."));
	updateStatusBar(intext);
}
function deleteStatus() {
	vsnode = document.getElementById("progress-bar-container");
	vsnode.parentNode.removeChild(vsnode);
	var vsnode = document.getElementById("progress-status");
	vsnode.parentNode.parentNode.removeChild(vsnode.parentNode);
}
</script>
<?
}

function autolink_report_start($total_count) {
	global $al_total_count;
	global $al_report_interval;
	global $al_progress_counter;
	$al_total_count = $total_count;
	if ($al_total_count == 0) $al_total_count = 1; // prevent division by zero
	$al_report_interval = intval($total_count/100);
	if ($al_report_interval == 0) $al_report_interval = 1; // prevent division by zero
	$al_progress_counter = 0;
	print "\n";
	autolink_report_make_progress_bar(); // to bootstrap the required code)
	print "\n";
	print '<script>';
	print "us($al_progress_counter,$al_total_count,'0');";
	print '</script>';
	ob_flush();
	flush();
}

function autolink_report_finish() {
	print "\n";
	print '<script>';
	print 'deleteStatus();';
	print '</script>';
	ob_flush();
	flush();
}

function autolink_report_progress($id) {
	global $al_progress_counter;
	global $al_total_count;
	global $al_report_interval;
	$al_progress_counter = $al_progress_counter + 1;
	if (($al_progress_counter % $al_report_interval == 0)) {
		print "\n";
		print '<script>';
		$intext = intval(intval($al_progress_counter)/intval($al_total_count)*100);
		print "us($al_progress_counter,$al_total_count,'$intext');";
		print '</script>';
		ob_flush();
		flush();
	}
}

/* manage screen: end progress bar functions */

$autolink_errors = array();
$autolink_old_error_handler = array();
$autolink_old_html_errors_status = array();

/* code to make a backtrace
	if (strstr($msg,'unserialize():') === false)
		if ($errorcode == 8) {
			print "<pre>$msg\n\n";
			print_r(debug_backtrace());
			die;
		}
*/

function autolink_trap_error_handler ($errorcode,$msg) {
	global $autolink_errors;
	if (strstr($msg,'unserialize():') === false)
		array_push($autolink_errors,array($errorcode,$msg));
}

function autolink_format_error_report($report) {
	$string = "";
	if ($report) {
	    $string .= "<ul>";
	    foreach($report as $r) {
		$string .=  "<li>";
		$code = "".$r[0];
		if ($r[0] == E_NOTICE) $code = "Notice";
		if ($r[0] == E_USER_NOTICE) $code = "User notice";
		if ($r[0] == E_ERROR) $code = "Error";
		if ($r[0] == E_USER_ERROR) $code = "User error";
		if ($r[0] == E_WARNING) $code = "Warning";
		if ($r[0] == E_USER_WARNING) $code = "User warning";
		$string .=  $code .": " . htmlspecialchars($r[1]);
		$string .=  "</li>";
	    }
	    $string .=  "</ul>";
	}
	return $string;
}

function autolink_trap_errors() {
	global $autolink_old_error_handler;
	global $autolink_old_html_errors_status;

	array_push($autolink_old_error_handler,set_error_handler("autolink_trap_error_handler"));
	array_push($autolink_old_html_errors_status,ini_get("html_errors"));
	ini_set("html_errors",false);
}

function autolink_halt_error_trap_and_return() {
	global $autolink_old_error_handler;
	global $autolink_old_html_errors_status;
	global $autolink_errors;

	$old_error_handler = array_pop($autolink_old_error_handler);
	restore_error_handler();
	ini_set("html_errors",array_pop($autolink_old_html_errors_status));
	$errors = $autolink_errors;
	$autolink_errors = array();
	return $errors;
}

function autolink_the_edit_post_link($id) {
	global $user_ID; get_currentuserinfo();
	if ( !user_can_edit_post($user_ID, $id) ) {
		return;
	}
	if ( is_attachment() ) return;
	else {
		$file = 'post';
		$link = "Edit";
		$location = get_settings('siteurl') . "/wp-admin/{$file}.php?action=edit&amp;post=$id";
		return "<a href=\"$location\" class='edit'>$link</a>";
	}
}

function autolink_the_view_post_link($id) {
	return '<a href="' . get_permalink($id) . '" class="edit">' . "View" . "</a>";
}

function autolink_format_mass_report($report) {
	$togglejs = "<script type='text/javascript' language='javascript'>
	function togglemessages(postid) {
		var element = document.getElementById('messages-post-' + postid.toString());
		if (element.getAttribute('style') == 'display: none;') {
			element.setAttribute('style','position: fixed; color: black; background: white; width: 80%; height: 80%; overflow: scroll; display: block; top: 10%; left: 10%; border: 2px outset #666666;');
			if (!element.getAttribute('closediv')) {
				var closediv = document.createElement('input');
				closediv.setAttribute('type','button');
				closediv.setAttribute('value','Close');
				closediv.setAttribute('style','float:right; margin: 0;');
				//closediv.appendChild(document.createTextNode('Click here to close this window'));
				closediv.setAttribute('onclick','togglemessages('+postid.toString()+');');
				element.setAttribute('closediv',closediv);
				element.insertBefore(closediv,element.firstChild);
			}
			element.firstChild.focus();
		}
		else {
			element.setAttribute('style','display: none;');
			element.previousSibling.focus();
		}
	}
	</script>";

	$string = "";
	if ($report) {
	    $string = $togglejs;
	    $string .= '<table width="100%" style="margin-left: auto; margin-right: auto;" cellpadding="3" cellspacing="3">';
	    $string .= "<th>ID</th><th>Title</th><th>Action</th><th></th><th></th><th></th>";
	    foreach($report as $r) {
		$alternate = $alternate ? "" : "class='alternate'";
		$string .= "<tr $alternate>";
		$string .=  "<td>{$r[0]}</td>";
		$string .= "<td>" . get_the_title($r[0]) . "</td>";
		if ($r[1] == "invalidxhtml") $msg = "Skipped (invalid XHTML)";
		elseif ($r[1] == "unchanged") $msg = "Unchanged";
		elseif ($r[1] == "autolinked") $msg = "Contents future-proofed";
		else $msg = $r[1];
		$string .= "<td nowrap='nowrap'>$msg</td>";
		$messages = $r[2];
		if ($messages) {
			$link = "javascript:togglemessages({$r[0]});";
			$popper = "<a href=\"$link\" class='edit'>Messages</a>";
			$messages = " " . $popper .
				"<div id='messages-post-{$r[0]}' style='display: none;'>$messages</div>";
		}
		$string .= "<td>$messages</td>";
		$view = autolink_the_view_post_link($r[0]);
		$string .= "<td>$view</td>";
		$edit = autolink_the_edit_post_link($r[0]);
		$string .= "<td>$edit</td>";
		$string .= "</tr>";
		print $string; $string = "";
	    }
	    $string .=  "</table>";
	    print ($string); $string = "";
	} else {
		print ("<p style='font-weight: bold'>Nothing to report.  No posts or pages were in need of modification.</p>");
	}
}


function autolink_manage_screen() {
?>
<div class="wrap">

<h2>Process all posts and pages</h2>

<?php if (!autolink_user_requested_futureproof()) { ?>
<p>WordPress AutoLink will replace absolute hyperlinks to posts, pages and uploads with <code>post:</code> and <code>content:</code> shortcuts.  This way, when you move to a different Web hosting, change domain name or reorganize your permalink structure, your hyperlinks and referenced files won't be broken. You'll be future-proofing your information.</p>
<p>WordPress AutoLink will also canonicalize the markup for each post.  This might mean minor changes in whitespace within tags, or replacement of some entities by their corresponding characters, but no destructive changes will be performed.</p>
<p>WordPress AutoLink will skip any post or page that contains invalid XHTML &mdash; which is a quick way of finding out if your pages have invalid XHTML (but is no replacement for <a href="http://rudd-o.com/projects/wp-validator/">the WordPress XHTML validator</a>).</p>
<?php } else { ?>
<p id="slated4removal1">WordPress AutoLink is future-proofing your content.  Please wait until the process is completed.</p>
<?php } ?>

<p id="slated4removal2">Once the process is finished, you will see a report.  If the process aborts unexpectedly, please increase the maximum execution time (<code>max_execution_time</code> directive) and the memory limit (<code>memory_limit</code> directive) in your PHP configuration (<code>php.ini</code> or <code>.htaccess</code>, whichever you prefer).</p>

<?php if (autolink_user_requested_futureproof()) { ?>
	<?php 
		$report = autolink_mass_simplify(
			autolink_user_requested_futureproof_committed(),
			"autolink_report_start","autolink_report_finish","autolink_report_progress");
	?>
	<script language="javascript" type="text/javascript">
		var d = document.getElementById("slated4removal1"); d.parentNode.removeChild(d);
		d = document.getElementById("slated4removal2"); d.parentNode.removeChild(d);
	</script>
	<p>The process is finished.  Here's a report of what WordPress AutoLink <?php if (autolink_user_requested_futureproof_committed()) print "did."; else print "would have done. Review each change in detail using the Messages links, edit each entry as you see fit and re-run the preview as many times as you want.  Once you're ready to future-proof your content, press the <em>Future-proof my content</em> button to have the changes committed to the database."; ?></p>
	<?php autolink_format_mass_report($report); ?>
<?php } ?>

<form action="" method="POST"><p class="submit"><input type="submit" name="futureproof" value="Preview what would happen"/> <input type="submit" name="futureproofcommit" value="Future-proof my content now"/></p></form>

</div>

<div class="wrap">

<h2>WordPress AutoLink</h2>

<p class="credit">Created by <a href="http://rudd-o.com/">Rudd-O</a>.  Get the latest version at <a href="http://rudd-o.com/projects/wp-autolink/">the WordPress AutoLink Web site</a>.</p>

</div>
<?php
}

function autolink_add_menu() {
	add_management_page('AutoLink', 'AutoLink', 1, __FILE__, 'autolink_manage_screen');
}

/* start dependency checkers */

function autolink_notactive_warning() {
	autolink_display_warning("autolink-notactive","submenu","WordPress AutoLink is not active",'Your PHP setup lacks the <code>DomDocument</code> class.  The XML extension for PHP needs to be installed on your Web server.');
}

function autolink_deps_satisfied() {
	if (!class_exists("DomDocument")) return false;
	return true;
}

function autolink_check_deps_and_warn() {
	if (!autolink_deps_satisfied()) autolink_notactive_warning();
}

add_action('admin_head','autolink_check_deps_and_warn');

/* end dependency checkers */

/* start setup */

function autolink_filter_content($content) { return autolink_render_for_display($content); }
function autolink_filter_excerpt($content) { return autolink_render_for_display($content); }
function autolink_filter_excerpt_rss($content) { return autolink_render_for_display($content); }
function autolink_filter_content_save_pre($content) { return addslashes(autolink_simplify(stripslashes($content))); }
function autolink_filter_excerpt_save_pre($content) { return addslashes(autolink_simplify(stripslashes($content))); }
function autolink_filter_format_to_edit($content) {
	$content = autolink_uftes($content);
	$content = autolink_render_for_editing($content);
	$content = autolink_rftes($content);
	/* first undo the format_to_edit, then pass through the renderer, then redo the format_to_edit munging */
	/* FIXME there's gotta be a better way to do this! And I don't mean that in a Perlish sense! */
	return $content;
}

function autolink_unfuck_singleton_tags($content) {
	$newcontent = preg_replace('|<a id="more-(\d+)"/>|','<a id="more-\1"></a>',$content);
	return $newcontent;
}

if (autolink_deps_satisfied()) {
	add_filter('the_content', 'autolink_filter_content');
	add_filter('the_excerpt', 'autolink_filter_excerpt');
	add_filter('the_excerpt_rss', 'autolink_filter_excerpt_rss');
	add_filter('content_save_pre', 'autolink_filter_content_save_pre',0);
	add_filter('excerpt_save_pre', 'autolink_filter_excerpt_save_pre',0);
	add_filter('content_edit_pre', 'autolink_filter_format_to_edit',0);
	add_action('admin_menu', 'autolink_add_menu');
}

/* end setup */

?>
