1<?php
2/**
3 *   @author Myron Turner <turnermm02@shaw.ca>
4 *   @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
5*/
6// must be run within Dokuwiki
7if(!defined('DOKU_INC')) die();
8class action_plugin_xtern extends DokuWiki_Action_Plugin {
9   	private   $accumulator = null;
10    private $current;
11	function __construct() {
12		$this->accumulator = metaFN('xtern:accumulator','.ser');
13	}
14    public function register(Doku_Event_Handler $controller) {
15       $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'handle_ajax_call_unknown');
16       $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'curl_check');
17       $controller->register_hook('IO_WIKIPAGE_READ', 'AFTER', $this, 'handle_wiki_read');
18       $controller->register_hook('TPL_CONTENT_DISPLAY', 'BEFORE', $this, 'handle_wiki_content');
19       $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'BEFORE', $this, 'handle_page_save');
20
21    }
22
23    /**
24     * @param Doku_Event $event  event object by reference
25     * @param mixed      $param  [the parameters passed as fifth argument to register_hook() when this
26     *                           handler was registered]
27     * @return void
28     */
29
30   public function curl_check(Doku_Event $event, $param) {
31        global $USERINFO,$JSINFO,$ID;
32        $admin = false;
33           if(isset($USERINFO)) {
34              $groups = $USERINFO['grps'];
35              if(in_array('admin', $groups)) $admin = true;
36           }
37         if($admin && !function_exists("curl_init"))  {
38             msg($this->getLang('nocurl'),2);
39             return;
40         }
41      	$this->accumulator = metaFN('xtern:accumulator','.ser');
42		if($this->getConf('noicons')) {
43            $JSINFO['xtern_disable'] = '1';
44		}
45     	if($this->getConf('alt_div')) {
46            $JSINFO['xtern_selector'] = "#" .$this->getConf('alt_div') . " a";
47		}
48        else if($this->getConf('alt_class')) {
49            $JSINFO['xtern_selector'] = '.' . $this->getConf('alt_class') . " a";
50		}
51        $skip = $this->getConf('skip_pages');
52         if($skip) {
53            $skip = preg_replace("/\s+/","",$skip) ;
54            $skip = str_replace(',','|',$skip) ;
55            $regex = "#^($skip)$#";
56            if(preg_match($regex,$ID)) {
57                 $JSINFO['xtern_skip'] = 1;
58            }
59         }
60   }
61
62    public function handle_ajax_call_unknown(Doku_Event $event, $param) {
63      if ($event->data !== 'extern_url') {
64        return;
65      }
66
67      global $lang,$INPUT;
68      $event->stopPropagation();
69      $event->preventDefault();
70       $url = $INPUT->str('url');
71       if(!function_exists("curl_init")) {
72           echo "NOCURL";
73           return;
74       }
75       $url = urldecode($url);
76       $ch = curl_init($url);
77	   if($this->getConf('ca_required')) {
78            curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . "/ca/cacert.pem");
79            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
80	   }
81		curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
82		curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1);
83		curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
84		curl_setopt($ch,CURLOPT_TIMEOUT,10);
85        curl_setopt($ch, CURLOPT_NOBODY, 1); //just fetch headers
86		$output = curl_exec($ch);
87        $curl_errno = curl_errno($ch);
88        if($curl_errno) {
89            if($curl_errno == "28") {
90                $status = "408";
91            }
92            else if($curl_errno == "60") {
93                $status = "495";
94            }
95            else $status = $curl_errno;
96        }
97		else $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
98		curl_close($ch);
99		echo "$status";
100        return 1;
101    }
102
103    function handle_wiki_read(Doku_Event $event, $param) {
104        global $INPUT, $ACT;
105		if($event->data[3]) {  //by-pass revision
106			return;
107		}
108        $act = act_clean($ACT);
109        if($act != 'edit') return;
110        if(!file_exists($this->accumulator)) return;
111        $id = $INPUT->str('id');
112        $id = str_replace(array('/','\\'), ':', $id);
113        $ar = unserialize(file_get_contents($this->accumulator));
114        $srch = array('__\s*BROKEN-LINK:','LINK-BROKEN\s*__') ;
115        $event->result = preg_replace("#$srch#", "",$event->result);
116        $event->result = str_replace($srch,"",$event->result);
117        if(!empty($ar[$id])) {
118        foreach($ar[$id] as $url) {
119           $this->update_wiki_page($event->result, $url) ;
120        }
121        }
122
123        //__BROKEN-LINK: __ BROKEN-LINK:[
124       $event->result = preg_replace('/__\s*BROKEN-LINK:__\s*BROKEN-LINK:/ms', '__ BROKEN-LINK:', $event->result);
125       $event->result = preg_replace('/\s*LINK-BROKEN\s*__\s*LINK-BROKEN\s*__/ms', 'LINK-BROKEN__', $event->result);
126       $event->result = preg_replace('/_*\s*BROKEN-LINK:_*\s*BROKEN-LINK:/ms', '__BROKEN-LINK:  ',  $event->result);
127       $event->result = preg_replace('/LINK-BROKEN__LINK-BROKEN__/ms', 'LINK-BROKEN__',  $event->result);
128       $event->result = preg_replace('/BROKEN-LINK:\s+/ms', 'BROKEN-LINK: ',  $event->result);
129       $event->result = preg_replace('/__BROKEN-LINK: \s*_*\s* BROKEN-LINK:/ms','__ BROKEN-LINK:',$event->result);
130
131    }
132
133    function update_wiki_page(&$result, $url)
134    {
135        msg(($url) , 2);
136        $this->current = $url;
137  //  $result = preg_replace_callback("|(?<!LINK:)(\[\[)?(" . preg_quote($url) . "(\|)*([^\]]+)*(\]\])?)[\s]*|ms", function ($matches)
138        $result = preg_replace_callback("|(?<!__LINK:)(\[\[)?(" . preg_quote($url) . "(\|)*([^\]]+)*(\]\])?)[\s]*|ms", function ($matches)
139        {
140            $test = preg_split("/[\s]+/", $matches[2]);
141            foreach ($test as $piece)
142            {
143                if (strpos($piece, 'http') !== false)
144                {
145                    if (strpos($piece, $this->current) !== false && strpos($matches[0], '-LINK:' . $piece) === false)
146                    {
147                        if ($matches[1] == '[[')
148                        {
149                            $link = preg_quote($this->current);
150                            $matches[0] = preg_replace("#\[\[($link.*?)\]\]#ms", "__ BROKEN-LINK:[[$1]] LINK-BROKEN __", $matches[0]);
151                        }
152                        else
153                        {
154                            $matches[0] = str_replace($piece, "__ BROKEN-LINK:" . $piece . " LINK-BROKEN __", $matches[0]);
155                        }
156                    }
157                }
158            }
159
160            return $matches[0];
161        }
162        , $result);
163    }
164
165  function handle_wiki_content(Doku_Event $event, $param) {
166     global $ACT;
167
168	 if($ACT == 'preview') {
169         return;
170     }
171     else if($this->getConf('conceal')) {
172     $event->data = preg_replace('#\<em\s+class=(\"|\')u(\1)\>\s*BROKEN\-LINK\:(.*?)LINK\-BROKEN\s*</em>#',"$3",$event->data);
173     return;
174     }
175   }
176  function handle_page_save(Doku_Event $event, $param) {
177        global $INPUT;
178		$url = $INPUT->str('xtern_url');
179		if(!isset($url) || empty($url)) return;
180        if($event->data['contentChanged']) return;
181        if(strpos($event->data['newContent'], 'BROKEN-LINK:') !== false) {
182            $event->data['contentChanged'] = true;
183        }
184    }
185
186    function write_debug($data) {
187	  return;
188      $debug_handle=fopen(DOKU_INC.'xtern.txt', 'wb');
189      if(!$debug_handle) return;
190      fwrite($debug_handle, $data);
191      fclose($debug_handle);
192   }
193
194 }
195