1<?php
2if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../../').'/');
3if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
4require_once(DOKU_PLUGIN.'action.php');
5
6/**
7 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
8 * @author     Myron Turner <turnermm02@shaw.ca>
9 */
10
11class action_plugin_openas extends DokuWiki_Action_Plugin {
12
13      private $ext = '.txt';
14	  private $locks_set=false;
15	  private $locked_fn;
16    /**
17     * Constructor
18     */
19    function __construct() {
20
21	     $this->locked_fn = $this->metaFilePath('locks','ser',false);
22	}
23
24    function register(Doku_Event_Handler $controller) {
25        $controller->register_hook('DOKUWIKI_STARTED', 'BEFORE', $this, 'openas_preprocess');
26		$controller->register_hook('DOKUWIKI_DONE', 'BEFORE', $this, 'update_locked_pages');
27    }
28
29
30	/**
31	    $_REQUEST['saveas_orig']: id of the original page which will be moved or copied to a new name
32	    $_REQUEST['id'] or $INFO['id']: name of the new page
33	*/
34    function openas_preprocess(Doku_Event $event){
35	   global $INFO;
36         if(!$this->check_url()) return;
37
38         if(isset($_REQUEST['openas'])) {
39            $new_file = wikiFN($INFO['id']);
40            if(file_exists($new_file) && isset($_REQUEST['saveas_orig'])) {
41                 // handle relative links for both save and move
42                  $this->update_relative_links($_REQUEST['id'],$_REQUEST['saveas_orig']) ;
43                if($_REQUEST['openas'] == 'delete') {
44			      $this->get_backs($_REQUEST['id'],$_REQUEST['saveas_orig']) ;
45                  $file = wikiFN($_REQUEST['saveas_orig']);
46                  if(file_exists($file)&&!$this->locks_set) @unlink($file);
47              }
48        }
49        }
50
51
52    }
53
54	function  get_backs($id,$orig) {
55		$backlinks = ft_backlinks($orig);
56
57		 foreach($backlinks as $backlink) {
58			if(!checklock($backlink)) {
59			lock($backlink);
60			}
61		}
62
63		$locked_array=$this->get_locked_array() ;
64         $locks_found = false;
65		 foreach($backlinks as $link) {
66			if(checklock($link)) {
67			   $this->locks_set = true;
68			   $locked_array[$link] = array($id,$orig);
69			   continue;
70			}
71			$this->resolve_ids($id,$orig,$link);
72		    unlock($link);
73		}
74		if($this->locks_set) {
75		    io_saveFile($this->locked_fn,serialize($locked_array));
76		}
77	}
78
79	/**
80	  Determines the absolute link for any relative links in the original page
81	  Then replaces relative links in moved page with the absolute links
82	  $c_link in the  create_function will hold the absolute link for an id based on the
83	  resolved link from the original page
84
85      @params
86 	  $new_id: page to which original is being moved
87	  $orig_id: page which is being moved and deleted
88	*/
89	function update_relative_links($new_id, $orig_id) {
90	    global $orig_namespace, $openas_debug;
91		$orig_namespace = rtrim(getNS($orig_id),':') . ':';
92		$openas_debug = $this;
93        $current_wikifn=wikiFN($new_id);
94		$data = io_readFile($current_wikifn);
95		$metafn=$this->metaFilePath($orig_id,'orig');
96
97		io_saveFile($metafn,$data);
98
99	    $data = preg_replace_callback('/\[\[(.*?)\]\]/',
100		     create_function(
101			   '$matches',
102			   'global $openas_debug,$orig_namespace;
103			   $link_array = explode("|",$matches[1]);
104			   $c_link = $link_array[0];
105			   $link_text = isset($link_array[1]) ? $link_array[1] : "";
106			   resolve_pageid($orig_namespace,$c_link,$c_exists);
107			   if($c_exists) {
108				   return "[[:$c_link|$link_text]]";
109			   }
110			   return $matches[0];'
111		     )	,
112		$data
113		);
114
115		$dir = dirname($current_wikifn);
116	    $fname = basename($current_wikifn, '.txt');
117		$path = "$dir/$fname" . $this->ext;
118		io_saveFile($path,$data);
119
120	}
121	/**
122	    This function updates all links in the backlink page which reference the
123		page being deleted.  The updated links will now refer to the new page.
124		The updated links will be absolute links.
125	     @params:
126		 $orig_id: deleted page
127		 $new_id: page to which $orig_id is being moved
128		 $curid: the page which is being currently being updated as determined
129		            from the backlinks array
130	*/
131	function resolve_ids($new_id, $orig_id, $curid) {
132        $current_wikifn=wikiFN($curid);
133        if(!$current_wikifn) return;
134
135		global  $current_ns;
136		global $openas_debug;
137		global $old_id;
138		global $new_page_id;
139		$old_id = $orig_id;
140		ltrim($new_id,':');
141		$new_page_id = ':' . $new_id;
142
143		$current_ns = rtrim(getNS($curid),':') . ':';
144
145		if(!function_exists("openas_check_pageid")) {
146
147		    function openas_check_pageid($matches) {
148			    global $openas_debug,$old_id,$current_ns,$new_page_id;
149			    $link_array = explode('|',$matches[1]);
150			    $c_link = $link_array[0];
151
152			    resolve_pageid($current_ns,$c_link,$c_exists);
153
154			     if($c_exists) {   // found a link in the namespace of current page that relates to namespace of page being deleted (original page)
155					  if(preg_match("/$old_id/",$c_link)) {  //is this link id found in the current page
156						   list($name,$hash) = explode('#',$link_array[0]);
157						   if(isset($hash)) {
158							 $new_link = $new_page_id . "#" .$hash;
159						   }
160						   else $new_link = $new_page_id ;
161
162						   return '[[' . $new_link . ']]';
163					}
164
165			    }
166
167			   return '[[' . $matches[1] . ']]';
168			}
169
170		}
171		$data = io_readFile($current_wikifn);
172        $metafn = $this->metaFilePath($curid);
173
174		io_saveFile($metafn,$data);
175
176	    $data = preg_replace_callback('/\[\[(.*?)\]\]/', "openas_check_pageid",$data);
177
178		$dir = dirname($current_wikifn);
179	    $fname = basename($current_wikifn, '.txt');
180		$path = "$dir/$fname" . $this->ext;
181		io_saveFile($path,$data);
182	}
183
184  function metaFilePath($current_id, $ext='mvd', $numbered=true) {
185    $namespace = 'openas:' . $current_id;
186
187	if($numbered) {
188	    for($i=1; ; $i++) {
189		    $metafnn = metaFN($namespace,  '.' . "$i.$ext");
190			if(!@file_exists($metafnn)) {
191			    return $metafnn;
192			}
193        }
194	}
195
196      $metafn = metaFN($namespace,  '.' . $ext);
197	   return $metafn;
198  }
199
200  /**
201   		 $orig_id: deleted page
202		 $new_id: page to which $orig_id is being moved
203		 $curid: the page which is being currently being updated as determined
204		            from the backlinks array
205
206 */
207  function save_locked($new_id,$orig_id,$back_link) {
208      $this->locked_array[$back_link] = array($new_id,$orig_id);
209  }
210
211  function get_locked_array() {
212	 if(@file_exists($this->locked_fn)) {
213		  return unserialize(io_readFile($this->locked_fn,false));
214	 }
215
216	 return array();
217  }
218
219  function update_locked_pages(Doku_Event $event) {
220     global $ID;
221	 $locked_array=$this->get_locked_array() ;
222
223	 if(isset($locked_array[$ID])) {
224	    //  $this->ext = '.locked2.txt';
225		  $new_id = $locked_array[$ID][0];
226		  $orig_id = $locked_array[$ID][1];
227		  $this->resolve_ids($new_id, $orig_id, $ID);
228	 }
229	 unset($locked_array[$ID]);
230	 io_saveFile($this->locked_fn,serialize($locked_array));
231	 if(empty($locked_array)) {
232         $file = wikiFN($orig_id);
233         if(file_exists($file)) @unlink($file);
234	  }
235
236  }
237
238  function check_url() {
239      global $INPUT,$USERINFO;
240
241      if(empty($USERINFO)) {
242          $action = $INPUT->get->str('openas');
243          if($action) {
244              $db = DOKU_BASE;
245              $default =  "${db}lib/plugins/openas/images/404.jpg";
246              $fourOhfour = $this->getConf("404");
247              if(!$fourOhfour) $fourOhfour = $default;
248              header("Location: $fourOhfour"); /* Redirect browser */
249              return false;
250          }
251      }
252      //id=tower2&saveas_orig=tower&openas=delete
253      $newid = $INPUT->get->str('id');
254      $saveas_orig = $INPUT->get->str('saveas_orig');
255      $action = $INPUT->get->str('openas');
256      if(!$action) return false;
257
258      resolve_pageid(getNS($newid), $newid, $exists);
259      $newid = cleanID($newid);
260      $auth_newid = auth_quickaclcheck($newid);
261
262      resolve_pageid(getNS($saveas_orig), $saveas_orig, $exists);
263      cleanID($saveas_orig);
264      $auth_origid = auth_quickaclcheck($saveas_orig);
265
266     // msg("$action original page:  $saveas_orig // " . $auth_origid);
267     // msg("new page: $newid //". $auth_newid );
268
269     switch($action)
270     {
271        case 'delete':
272           if($auth_origid < AUTH_EDIT) {
273               $nodel = $this->getLang('nodelete');
274               msg("1. $nodel $saveas_orig");
275               return false;
276           }
277            if($auth_newid < AUTH_CREATE) {
278                $nocreate = $this->getLang('nocreate');
279                msg("2. $nocreate $id");
280                return false;
281            }
282           return true;
283
284        case 'save':
285           if($auth_newid < AUTH_CREATE) {
286               $nocreate = $this->getLang('nocreate');
287               msg("3. $nocreate $newid");
288               return false;
289          }
290          if($auth_origid < AUTH_EDIT) {
291             $nocopy = $this->getLang('nocopy');
292              msg("4. $nocopy $saveas_orig");
293              return false;
294          }
295           return true;
296
297        default:
298           return false;
299     }
300
301     return false;
302  }
303
304  function write_debug($what,$pre=false) {
305     if(is_array($what)) $what = print_r($what,true);
306     if($pre) {
307        msg('<pre>' . $what . '</pre>');
308     return;
309     }
310     $handle = fopen("openas.txt", "a");
311     fwrite($handle,"$what\n");
312     fclose($handle);
313  }
314
315} //end of action class
316?>
317