1<?php
2/**
3 * @license    GPL 3 (http://www.gnu.org/licenses/gpl.html)
4 * @author     Martin Schulte <lebowski[at]corvus[dot]uberspace[dot]de>, 2013
5 */
6
7//error_reporting (E_ALL | E_STRICT);
8//ini_set ('display_errors', 'On');
9
10
11// must be run within Dokuwiki
12if (!defined('DOKU_INC')) die();
13
14if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
15if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
16if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
17
18require_once(DOKU_PLUGIN.'action.php');
19
20class action_plugin_owncloud extends DokuWiki_Action_Plugin{
21
22	// constants
23	const FILEUPDATE = 1;
24	const FILEREMOVE = 2;
25	const NSREMOVE = 3;
26	const WIKISTORAGE = 'wiki';
27
28
29	/**
30	 * Register all hooks
31	*/
32	function register(&$contr) {
33		$contr->register_hook('IO_WIKIPAGE_WRITE','BEFORE',$this,'write');
34		//$contr->register_hook('PARSER_WIKITEXT_PREPROCESS','BEFORE',$this,'preprocess');
35		$contr->register_hook('MEDIA_UPLOAD_FINISH','AFTER',$this,'filecache',self::FILEUPDATE);
36		$contr->register_hook('MEDIA_DELETE_FILE','AFTER',$this,'filecache',self::FILEREMOVE);
37		$contr->register_hook('IO_NAMESPACE_DELETED','AFTER',$this,'filecache',self::NSREMOVE);
38		$contr->register_hook('RENDERER_CONTENT_POSTPROCESS','AFTER',$this,'mediaOnThisPage');
39		$contr->register_hook('TPL_ACT_RENDER','AFTER',$this,'mediaOnThisPageREV');
40
41
42
43	}
44
45    /**
46    * Returns the path for the correspondig fileID (from table OC_filecache)
47    * Adds a list with all media used on this page to the end of the page
48    * Skips older revisions.
49    */
50    function mediaOnThisPage(&$event, $param){
51		global $ID;
52		global $ACT;
53		global $REV;
54		//$event->data[1] .="<h1>Dies ist noch zu sehend</h1>";
55		if($ACT != 'show') return false;
56		if($REV != 0) return false; // TPL_ACT_RENDER for older revisions
57		if(!page_exists($ID)) return false;
58		$helper = $this->loadHelper('owncloud',false);
59		$list = $helper->getMediaOfThisPage($ID);
60		if(!$list) return false;
61		$event->data[1] .= '<h1 id="headingusedmedia">'.$this->getLang('filesOnThisSide').'</h1>';
62		$event->data[1] .= $list;
63
64	}
65
66	/**
67    * Returns the path for the correspondig fileID (from table OC_filecache)
68    * Adds a list with all media used on this page to the end of the page
69    * Skips older revisions.
70    */
71	function mediaOnThisPageREV(&$event, $param){
72		global $REV;
73		global $ID;
74		if($REV == 0) return false; // see above
75		/* TODO this may not be the real media used on this page. Effectively
76		   this are the used media of the current page*/
77		echo '<h1 id="headingusedmedia">'.$this->getLang('filesOnThisSide').'</h1>';
78		$helper = $this->loadHelper('owncloud',false);
79		echo $helper->getMediaOfThisPage($ID);
80	}
81
82    /*
83     * Makes sure, that files uploaded or delete using the DokuWiki mediamanager
84     * are updated in the ownCloud database.
85     */
86    function filecache(&$event, $param){
87		global $conf;
88		global $INFO;
89		require_once($this->getConf('pathtoowncloud').'/lib/base.php');
90		$file = str_replace($conf['mediadir'],'/'.self::WIKISTORAGE,$event->data[1]);
91		OC\Files\Filesystem::init($_SERVER['REMOTE_USER'],'/'.$_SERVER['REMOTE_USER'].'/files');
92
93		switch($param){
94				case self::FILEUPDATE:	$file = str_replace($conf['mediadir'],'/'.self::WIKISTORAGE,$event->data[1]);
95										OC\Files\Cache\Updater::writeUpdate($file);
96										$this->fixDescription(str_replace($conf['mediadir'],'',$event->data[1]),2);// 2, because the medialog entry is already written
97										//OCA\DokuWiki\Storage::dokuwikiUploadFinish($file,$_SERVER['REMOTE_USER'],!$event->data[4]);
98										break;
99				case self::FILEREMOVE:	$file = str_replace($conf['mediadir'],'/'.self::WIKISTORAGE,$event->data['path']);
100										OC\Files\Cache\Updater::deleteUpdate($file);
101										break;
102				case self::NSREMOVE:	if($event->data[1] == 'media'){
103											$dir = '/'.self::WIKISTORAGE.'/'.str_replace(':','/',$event->data[0]);
104											OC\Files\Cache\Updater::deleteUpdate($dir);
105										}
106										break;
107
108
109
110		}
111
112	}
113
114    /**
115     * Add fileid or update filepath
116     *
117     * If file exists in the ownCloud database, the fileid will be add to the file parameters,
118     * if fileid exists as parameter, the path will be updated (if necessary)
119     * Changes will be write to disk
120     *
121     */
122	function write(&$event, $param){
123
124		$text = $event->data[0][1];
125		$helper = $this->loadHelper('owncloud',false);
126		global $ID;
127		$helper->dbQuery('DELETE FROM `*PREFIX*dokuwiki_media_use` WHERE `wikipage_hash` = ?', array(md5($ID)));
128		$event->data[0][1] = preg_replace('#\{\{(.+)\}\}#Uise', "'{{'.action_plugin_owncloud::buildLink('\\1',true).'}}'",$text);
129	}
130
131	/**
132     * The same as write, but only for preprocess, e. g. when choose preview.
133     *
134     */
135	function preprocess(&$event, $param){
136		$text = $event->data;
137		global $ACT;
138		echo "<h1>$ID</h1>";
139		$event->data = preg_replace('#\{\{(.+)\}\}#Uise', "'{{'.action_plugin_owncloud::buildLink('\\1',false).'}}'",$text);
140	}
141
142
143
144	/**
145     * Build the link with fileid or update the filepath if fileid is given.
146     * @param string $rawdata the wikitext
147     *
148     */
149	function buildLink($rawdata, $write = false){
150		global $ID;
151		$helper = $this->loadHelper('owncloud',false);
152		if(!$helper) return $rawdata;
153		$parts = explode("|",$rawdata);
154		$link = array_shift($parts);
155		// Save alignment
156		$ralign = (bool)preg_match('/^ /',$link);
157		$lalign = (bool)preg_match('/ $/',$link);
158		// delete whitespaces
159		$link = trim($link);
160		if($helper->isExternal($link)) return $rawdata;
161		//split into src and parameters (using the very last questionmark) from /inc/parser/handler.php
162		$pos = strrpos($link,'?');
163		if($pos != false){
164			$src   = substr($link,0,$pos);
165			$param = substr($link,$pos+1);
166		}else{
167			$src   = $link;
168			$param = '';
169		}
170		if(preg_match('#fileid=(\d+)?#i',$param,$match)){
171			($match[1]) ? $fileid = intval($match[1]) : $fileid = 0;
172		}else{
173			$fileid = 0;
174		}
175		$desc = implode("|",$parts);
176		// get fileID
177		/*if(count($parts) > 1  ){ // We've a fileid
178			$last = array_pop($parts);
179			$fileid = intval($last); // Last element maybe fileid
180			$desc = implode("|",$parts); // The rest is the description, can contain |
181			if($fileid == 0 ) $desc .= "|".$last; // no fileid, is part of description
182		}else{
183			$fileid = 0;
184			$desc = array_shift($parts);
185		}*/
186		// db access
187
188		if($fileid > 0){ // Then find filename from id
189			$path = $helper->getFilenameForID($fileid);
190			if($path != ""){
191				$src = str_replace('/',':',$path);
192				$notfound = false;
193			}else{
194				$notfound = true;
195			}
196		}else{
197			$notfound = true;
198		}
199		// We have no file from id, look for id using source
200		if($notfound){ // Try to find ID from source
201			$oldsrc = $src;
202			resolve_mediaid(getNS($ID),$src, $exists);
203			if($exists){
204				$fileid = $helper->fileIDForWikiID($src);
205			}else{// Maybe directory
206				$fileid = $helper->fileIDForWikiID($oldsrc);
207				if($fileid != '' && $fileid > 0) $src = $oldsrc;
208			}
209
210			if($fileid == '' || $fileid < 1) return $rawdata;
211		}
212
213		if($write) $this -> mediaUse($fileid,$helper);
214		$param = preg_replace('#fileid=(\d+)?#i',"fileid=$fileid",$param,-1,$count);
215		if($fileid!='' && $fileid > 0 && $count < 1) $param = (($param != "") ? "$param&fileid=$fileid":"fileid=$fileid");
216		return (($ralign)?" ":"").":".$src.(($param != "") ? "?$param":"").(($lalign)?" ":"")."|".$desc;
217		//return (($ralign)?" ":"").$src.(($param != "") ? "?$param":"").(($lalign)?" ":"")."|".$desc."|".$fileid;
218	}
219
220	/**
221	 * Adds a fileid to and the wikiid to table dokuwiki_media_use
222	 */
223	function mediaUse($fileid, &$helper){
224		global $ID;
225		global $INFO;
226		$heading = (is_array($INFO['meta']['description']['tableofcontents']))?$INFO['meta']['description']['tableofcontents'][0]['title']:'';
227		$helper->dbQuery('INSERT IGNORE INTO `*PREFIX*dokuwiki_media_use` (`fileid`, `wikipage`,`wikipage_hash`,`firstheading`) VALUES (?,?,?,?)', array($fileid, $ID, md5($ID), $heading));
228	}
229
230	/**
231     * Put the last description/summary as new description (if it is not 'created' or 'deleted')
232     */
233	function fixDescription($file,$x=1){
234		global $conf;
235		global $lang;
236		$file = $conf['mediametadir'].'/'.$file.'.changes';
237		if(file_exists($file)){
238			$meta = file($file);
239			$desc = '';
240			$lines = 0;
241			if(!empty($meta)) $lines = count($meta);
242			if($lines >= $x ){
243				$xLine = $meta[$lines-$x];
244				$line = explode("\t", $xLine);
245				$desc = (isset($line[5]))?trim($line[5]):'';
246				if($desc == $lang['created'] || $desc == $lang['deleted'] ) $desc='';
247				// Set desc for the last line
248				$strip = array("\t", "\n");
249				$lastLine = array_pop($meta);
250				$line = explode("\t", $lastLine);
251				$line[5] = utf8_substr(str_replace($strip, ' ',htmlspecialchars($desc)),0,255);
252				array_push($meta,trim(implode("\t", $line))."\n");
253				io_saveFile($file,implode("", $meta));
254				return true;
255			}
256		}
257		return false;
258	}
259}
260