1<?php
2
3if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../../').'/');
4include_once(DOKU_INC . 'inc/init.php');
5if(file_exists(DOKU_INC . 'inc/Remote/Api.php')) {
6require_once(DOKU_INC . 'inc/Remote/ApiCore.php');
7require_once(DOKU_INC . 'inc/Remote/Api.php');
8require_once(DOKU_INC . 'inc/IXR_Library.php');
9}
10else {
11    require_once(DOKU_INC . 'inc/remote.php');
12    require_once(DOKU_INC . 'inc/RemoteAPICore.php');
13}
14//require_once('./scripts/createMetaTable.php');
15global $xcom_timezone, $xcom_current,$xcom_prefix,$conf;
16define ('PAGES', realpath(DOKU_INC . $conf['savedir']));
17$xcom_timezone = 'UTC'; // default timezone is set to Coordinated Univeral Time. You can reset your timezone here
18class remote_plugin_xcom extends DokuWiki_Remote_Plugin {
19    private $api, $server;
20    public function _getMethods() {
21        return array(
22            'getTime' => array(
23                'args' => array('int'),
24                'return' => 'date'
25            ),
26            'getMedia' => array(
27                'args' => array('string','string'),
28               'return' => 'array',
29               'doc' => 'returns list of media in page id named in args1, args 2 is optional namespace'
30            ),
31            'listNamespaces' => array(
32                'args' => array('string','array'),
33                'return' => 'array',
34                'doc' => 'returns list of wiki namespaces'
35            ),
36            'pageVersions' => array(
37                'args' => array('string','int'),
38                'return' => 'array',
39                'doc' => 'returns list of page versions'
40            ),
41           'getPageInfo' => array(
42                'args' => array('string'),
43                'return' => 'array',
44                'doc' => 'Returns a struct with info about the page, latest version.',
45                'name' => 'pageInfo'
46            ),
47           ' GetMetaData' => array(
48                'args' => 'string',
49                'return' => 'string',
50                'doc' => 'Returns metadata of one or more wiki pages',
51                'name' => 'GetMetaData'
52            ),
53        );
54    }
55
56     function  __construct() {
57          $iswin = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
58          if(!defined('DIRECTORY_SEPARATOR')) {
59             $iswin ? define("DIRECTORY_SEPARATOR", "\\") : define("DIREC TORY_SEPARATOR", "/");
60           }
61          if(class_exists("dokuwiki\Remote\APICore")) {
62              $this->api = new dokuwiki\Remote\APICore(new dokuwiki\Remote\Api());
63         }
64         else $this->api = new RemoteAPICore(new RemoteApi());
65     }
66    public function getTime($a) {
67        //return date("Y-m-d s",$a);
68        return date("Y-m-d H:i:s",$a);
69
70    }
71
72
73     public function listNamespaces($namespace="",$mask="") {
74      global $conf;
75       $rootns =  $conf['savedir'];
76       $rootns = ltrim($rootns,'./');
77       if($rootns == 'data') {
78           $rootns = DOKU_INC . $rootns;
79       }
80
81      if(!$namespace) {
82        $namespace = $rootns;
83      }
84       else $namespace = $rootns . '/pages/'. $namespace;
85      $namespace = rtrim($namespace, '/');
86      $folder_list = array();
87
88    $regex='';
89    $mask = trim($mask);
90    if($mask) {
91        $mask= json_decode($mask);
92        for($i=0; $i<count($mask) ;$i++) {
93            $mask[$i] = preg_quote($mask[$i]);
94        }
95        if(count($mask) > 1) {
96           $regex =  implode('|',$mask);
97        }
98         else if(is_array($mask)) {
99            $regex = $mask[0];
100         }
101         else $regex = $mask;
102        $regex =  "($regex)\b";
103   }
104
105     $result =$this->find_all_files($namespace,$regex);
106
107     $regex  = '#' . preg_quote($rootns) .'#';
108
109    for($i=0;$i<count($result); $i++) {
110          $result[$i] = preg_replace($regex,"",$result[$i]);
111          $result[$i] = preg_replace("/\/?pages/","",$result[$i]);
112          $result[$i] = str_replace('/',':',$result[$i]);
113
114   }
115      return $result;
116
117
118    }
119
120  /**
121    *    Based on  find_all_files() by kodlee at kodleeshare dot net
122    *         at  http://ca3.php.net/scandir:
123   */
124  function find_all_files($dir,$regex="")
125  {
126    $root = scandir($dir);
127
128   foreach($root as $value)
129    {
130        if($value === '.' || $value === '..') {continue;}
131         if($regex)  if(preg_match('#'. $regex .'#',"$dir/$value")) {continue;}
132         if(is_dir("$dir/$value") && is_readable("$dir/$value")) {
133                $result[]="$dir/$value";
134                foreach($this->find_all_files("$dir/$value",$regex) as $value)
135                {      if(!$regex) {
136                             $result[]="$value";
137                         }
138                         else  if(! preg_match('#'. $regex .'#',"$dir/$value")) {
139                            $result[]="$value";
140                        }
141
142                }
143           }
144    }
145      if(isset($result)) return $result;
146      return array();
147  }
148
149    public function getMedia($id,$namespace="") {
150          if($namespace) {
151              $id = "$namespace:$id";
152          }
153          $path =  metaFN($id,'.meta');
154
155
156          if(@file_exists($path)) {
157              $inf_str = file_get_contents($path);
158              $inf = @unserialize($inf_str);
159              if($inf['current']['relation']['media']) {
160                   return array_keys($inf['current']['relation']['media']);
161              }
162
163              $filename = wikiFN($id);
164              if(@file_exists($filename)) {
165                 $str = file_get_contents($filename );
166                 if(strpos($str,'{{') === false) return "0";
167                 preg_match_all('/{{(.*?)}}/ms',$str,$matches);
168                 $media = array();
169                 foreach($matches[1] as $file) {
170                    $result = explode('|', $file);
171                    $result = explode('?',$result[0]);
172                    $result = trim($result[0]);
173                    if(strpos($result,'http://')=== false && strpos($result,'>') === false ){
174                        $media[$result] = 1;
175                    }
176                }
177                $media = array_keys($media);
178                if(!empty($media) ) {
179                    return $media;
180                }
181              }
182
183              return "no media data in $path";
184          }
185          return "no data for $id";
186    }
187
188          /**
189     * Returns a list of available revisions of a given wiki page
190     * Number of returned pages is set by $conf['recent']
191     * However not accessible pages are skipped, so less than $conf['recent'] could be returned
192     *
193     * @author Michael Klier <chi@chimeric.de>
194     *
195     * @param string $id page id
196     * @param int $first skip the first n changelog lines
197     *                      0 = from current(if exists)
198     *                      1 = from 1st old rev
199     *                      2 = from 2nd old rev, etc
200     * @return array
201     */
202    public function pageVersions($id, $first = 0)
203    {
204        header("Access-Control-Allow-Origin: *");
205        return  json_encode($this->api->pageVersions($id, $first));
206}
207
208
209
210
211        /**
212     * Return some basic data about a page
213     *
214     * @param string $id page id
215     * @param string|int $rev revision timestamp or empty string
216     * @return array
217     * @throws AccessDeniedException no access for page
218     * @throws RemoteException page not exist
219     */
220    public function pageInfo($id, $rev = '') {
221       $info =  $this->api-> pageInfo($id, $rev = '');
222       $info['lastModified'] = $this->getTime($info['lastModified']);
223       return json_encode($info);
224    }
225
226    private function resolvePageId($id)
227    {
228        $id = cleanID($id);
229        if (empty($id)) {
230            global $conf;
231            $id = cleanID($conf['start']);
232        }
233        return $id;
234    }
235
236   function GetMetaData($id) {
237    global $xcom_timezone, $xcom_current,$xcom_prefix,$conf;
238    $contents="";
239    date_default_timezone_set($xcom_timezone);
240    $xcom_prefix = preg_replace("/.*?\/data\/meta/", "", $conf['metadir']);
241    $xcom_prefix = ($depth = str_replace('/', ':', $xcom_prefix)) ? $depth : '';
242    if($id === ':' || preg_match("/\:\*$/",$id)) {
243        $id = rtrim($id,':*');
244        $ns =  $conf['metadir'] .'/'. $id;
245
246        chdir($ns);
247        $this->recurse('.',$contents);
248    }
249    else {
250
251        $file = metaFN($id,'.meta');
252        $this->get_data($file,$id,$contents);
253    }
254
255
256    $contents = str_replace("<table.*?>\n</table>","",$contents);
257     return $contents;
258
259}
260
261
262function recurse($dir,&$contents) {
263    global $xcom_prefix;
264    $dh = opendir($dir);
265    if (!$dh) return;
266    $cur_dir = '/pages' . preg_replace('#^.*?data/meta#',"", getcwd());
267    while (($file = readdir($dh)) !== false) {
268        if ($file == '.' || $file == '..') continue;
269
270        if (is_dir("$dir/$file")) {
271          $this->recurse("$dir/$file",$contents);
272         }
273        if (preg_match("/\.meta$/", $file)) {
274            $store_name = preg_replace('/^\./', $xcom_prefix, "$dir/$file");
275            $id_name = PAGES ."$cur_dir${store_name}";
276            $id_name = preg_replace('/\.meta$/', '.txt',$id_name);
277            $this->get_data("$dir/$file",$id_name,$contents);
278            $contents .= "\n";
279        }
280    }
281
282    closedir($dh);
283}
284function get_data($file,$id_path,&$contents) {
285    global $xcom_current;
286    $data = file_get_contents($file);
287    $data_array = @unserialize(file_get_contents($file));
288    $creator =""; $creator_id="";
289
290    if ($data_array === false || !is_array($data_array)) return;
291    if (!isset($data_array['current'])) return;
292      $contents .= "\n<p>\n";
293    $contents .= "\n" . '<table style="border-top:2px solid">' ."\n";
294    $contents .= "<tr><td colspan='2'>$id_path</td></tr>\n";
295    $contents .= "<tr><td colspan='2'>$file</td></tr>\n";
296    $xcom_current = $data_array['current'];
297    $keys =  array('title','date','creator','last_change','relation');
298    foreach ($keys AS $header) {
299        switch($header) {
300            case 'title':
301                 $title = $this->getcurrent($header, null);
302                 $contents .= "<tr><td colspan='2'>Title: <b>$title</b></td></tr>\n";
303                 break;
304
305            case 'date':
306                 $this->process_dates($this->getcurrent('date', 'created'),$this->getcurrent('date', 'modified'),$contents);
307                 break;
308            case 'user':
309                if($creator || $creator_id) break;
310            case 'creator':
311                $creator = $this->getcurrent('creator', null);
312                $creator_id = $this->getcurrent('user', null);
313                $this->process_users($creator,$creator_id,$contents);
314                 break;
315
316            case 'last_change':
317                $last_change = $this->getSimpleKeyValue($this->getcurrent($header, null),"last_change",$contents);
318                 if($last_change) {
319                    $contents .=  "<tr><td colspan='3'  ></td>\n";
320                    $contents .= "<tr><td colspan='2' style='border-left: 2px solid #4169E1; color:#4169E1' ><b>Last Change</b></td>\n";
321                    $contents .= "<td>$last_change</td></tr>\n";
322                }
323                break;
324            case 'contributor':
325                 $this->contributors = $this->getSimpleKeyValue($this->getcurrent($header, null),$contents);
326                 break;
327            case 'relation':
328                $isreferencedby = $this->getcurrent($header,'isreferencedby');
329                $references = $this->getcurrent($header,'references');
330                $media = $this->getcurrent($header,'media');
331                $firstimage = $this->getcurrent($header,'firstimage');
332                $haspart = $this->getcurrent($header,'haspart');
333                $subject = $this->getcurrent($header,'subject');
334                $this->process_relation($isreferencedby,$references,$media,$firstimage,$haspart,$subject,$contents);
335                break;
336            default:
337
338                 break;
339            }
340
341        }
342       $contents .= "\n</table></p>\n";
343       $xcom_current = array();
344}
345
346/*
347*  @param array $ar metadata field
348*  @param string $which which field
349*/
350function getSimpleKeyValue($ar,$which="",&$contents) {
351    $retv = "";
352    $types = array('C'=>'<u>C</u>reate','E'=>'<u>E</u>dit','e' =>'minor <u>e</u>dit','D'=>'<u>D</u>elete',
353    'R'=>'<u>R</u>evert');
354    if(!is_array($ar)) return false;
355    $border = "";
356    foreach ($ar As $key=>$val) {
357        if(!empty($val)) {
358           if($which == 'last_change')  {
359               $border = " style='border-left: 2px solid #4169E1;'";
360               if($key == 'date') {
361                   $val = date("r", $val);
362                }
363                if($key == 'type')  {
364                    $val = $types[$val];
365                }
366           }
367
368          if(empty($val))  {
369               $retv .= "<tr><td  $border>$key:</td><td>$val</td></tr>\n";
370            }
371            else  $retv .= "<tr><td $border>$key:</td><td>$val</td></tr>\n";
372       }
373    }
374    return $retv;
375}
376
377function process_users($creator,$user,&$contents) {
378        if(empty($creator)) {
379            $contents .= "\n"; return;
380         }
381        $contents .= "<tr><td>Created by:</td><td> $creator (userid: $user)</tr></td>\n";
382}
383
384function process_dates($created, $modified,&$contents) {
385    $retv = "";
386
387    if ($created) {
388        $rfc_cr = date("r", $created);
389        $contents .= "<tr><td>Date created:</td><td>".$rfc_cr.
390        "</td><td>$created</td></tr>\n";
391        }
392
393    if ($modified) {
394        $rfc_mod = date("r", $modified);
395        $contents .= "<tr><td>Last modified:</td><td>" . $rfc_mod .
396        "</td><td>$modified</td></tr>\n";
397     }
398
399}
400
401function insertListInTable($list,$type,&$contents) {
402     $border = " style='border-left: 2px solid green;'";
403    if($list) $contents .= "<tr><td $border>$type</td><td>$list</td></tr>\n";
404}
405function process_relation($isreferencedby,$references,$media,$firstimage,$haspart,$subject,&$contents) {
406      if(!empty($isreferencedby) || !empty($references) || !empty($media) || !empty($firstimage)
407           && !empty($haspart ) &&!empty($subject)) {
408                $border = " style='border-left: 2px solid green;'";
409                $contents .=  "<tr><td colspan='3'  ></td>\n";
410                $contents .= "<tr><td colspan='2'  $border><b><span style='color:green'>Relation</span></b></td>\n";
411           }
412           else $border = "";
413    if(!empty($isreferencedby)) {
414        $list =  $this->create_list(array_keys($isreferencedby),$contents);
415        $this->insertListInTable($list,'Backlinks (isreferencedby)',$contents);
416    }
417    if(!empty($references)) {
418       $list =  $this->create_list(array_keys($references),$contents);
419        $this->insertListInTable($list,'Links (references)',$contents);
420    }
421    if(!empty($media)) {
422       $list =  $this->create_list(array_keys($media),$contents);
423        $this->insertListInTable($list,'Media',$contents);
424    }
425    if(!empty($firstimage)) {
426       $contents .= "<tr><td   $border>First Image</td><td>$firstimage</td></tr>";
427    }
428    if(!empty($haspart)) {
429       $list =  $this->create_list(array_keys($haspart),$contents);
430        $this->insertListInTable($list,'haspart',$contents);
431    }
432    if(!empty($subject)) {
433       $list =  $this->create_list(array_keys($subject),$contents);
434        $this->insertListInTable($list,'Subject',$contents);
435    }
436
437}
438
439function create_list($ar,&$contents) {
440    $list = "\n<ol>\n";
441    for($i=0; $i<count($ar); $i++) {
442        $list .= '<li>'. $ar[$i] . "</li>\n";
443    }
444     $list .= "</ol>\n";
445     return $list;
446}
447function getcurrent($which, $other) {
448    global $xcom_current;
449    if (!isset($xcom_current)) return "";
450    if ($other) {
451        if (isset($xcom_current[$which][$other])) {
452            return $xcom_current[$which][$other];
453        }
454    }
455    if (isset($xcom_current[$which]) && $other === null) {
456        return $xcom_current[$which];
457    }
458    return "";
459}
460}
461
462
463