1<?php
2
3namespace dokuwiki\Remote;
4
5use dokuwiki\Utf8\PhpString;
6use IXR\DataType\Base64;
7use IXR\DataType\Date;
8
9/**
10 * Provides wrappers for the API calls as they existed in API Version 11
11 *
12 * No guarantees are made about the exact compatibility of the return values.
13 *
14 * @deprecated
15 */
16class LegacyApiCore extends ApiCore
17{
18    /** @inheritdoc */
19    public function getMethods()
20    {
21        $methods = parent::getMethods();
22
23        return array_merge(
24            $methods,
25            [
26                'dokuwiki.getVersion' => new ApiCall([$this, 'legacyGetVersion'], 'legacy'),
27                'dokuwiki.login' => (new ApiCall([$this, 'legacyLogin'], 'legacy'))->setPublic(),
28                'dokuwiki.logoff' => new ApiCall([$this, 'legacyLogoff'], 'legacy'),
29                'dokuwiki.getPagelist' => new ApiCall([$this, 'legacyGetPagelist'], 'legacy'),
30                'dokuwiki.search' => new ApiCall([$this, 'legacySearch'], 'legacy'),
31                'dokuwiki.getTime' => new ApiCall([$this, 'legacyGetTime'], 'legacy'),
32                'dokuwiki.setLocks' => new ApiCall([$this, 'legacySetLocks'], 'legacy'),
33                'dokuwiki.getTitle' => (new ApiCall([$this, 'legacyGetTitle'], 'legacy'))->setPublic(),
34                'dokuwiki.appendPage' => new ApiCall([$this, 'legacyAppendPage'], 'legacy'),
35                'dokuwiki.createUser' => new ApiCall([$this, 'legacyCreateUser'], 'legacy'),
36                'dokuwiki.deleteUsers' => new ApiCall([$this, 'legacyDeleteUsers'], 'legacy'),
37                'wiki.getPage' => new ApiCall([$this, 'legacyGetPage'], 'legacy'),
38                'wiki.getPageVersion' => new ApiCall([$this, 'legacyGetPageVersion'], 'legacy'),
39                'wiki.getPageHTML' => new ApiCall([$this, 'legacyGetPageHTML'], 'legacy'),
40                'wiki.getPageHTMLVersion' => new ApiCall([$this, 'legacyGetPageHTMLVersion'], 'legacy'),
41                'wiki.getAllPages' => new ApiCall([$this, 'legacyGetAllPages'], 'legacy'),
42                'wiki.getAttachments' => new ApiCall([$this, 'legacyGetAttachments'], 'legacy'),
43                'wiki.getBackLinks' => new ApiCall([$this, 'legacyGetBackLinks'], 'legacy'),
44                'wiki.getPageInfo' => new ApiCall([$this, 'legacyGetPageInfo'], 'legacy'),
45                'wiki.getPageInfoVersion' => new ApiCall([$this, 'legacyGetPageInfoVersion'], 'legacy'),
46                'wiki.getPageVersions' => new ApiCall([$this, 'legacyGetPageVersions'], 'legacy'),
47                'wiki.putPage' => new ApiCall([$this, 'legacyPutPage'], 'legacy'),
48                'wiki.listLinks' => new ApiCall([$this, 'legacyListLinks'], 'legacy'),
49                'wiki.getRecentChanges' => new ApiCall([$this, 'legacyGetRecentChanges'], 'legacy'),
50                'wiki.getRecentMediaChanges' => new ApiCall([$this, 'legacyGetRecentMediaChanges'], 'legacy'),
51                'wiki.aclCheck' => new ApiCall([$this, 'legacyAclCheck'], 'legacy'),
52                'wiki.putAttachment' => new ApiCall([$this, 'legacyPutAttachment'], 'legacy'),
53                'wiki.deleteAttachment' => new ApiCall([$this, 'legacyDeleteAttachment'], 'legacy'),
54                'wiki.getAttachment' => new ApiCall([$this, 'legacyGetAttachment'], 'legacy'),
55                'wiki.getAttachmentInfo' => new ApiCall([$this, 'legacyGetAttachmentInfo'], 'legacy'),
56                'dokuwiki.getXMLRPCAPIVersion' => (new ApiCall([$this, 'legacyGetXMLRPCAPIVersion'], 'legacy'))
57                    ->setPublic(),
58                'wiki.getRPCVersionSupported' => (new ApiCall([$this, 'legacyGetRPCVersionSupported'], 'legacy'))
59                    ->setPublic(),
60            ]
61        );
62    }
63
64    /**
65     * This returns a XMLRPC object that will not work for the new JSONRPC API
66     *
67     * @param int $ts
68     * @return Date
69     */
70    protected function toDate($ts)
71    {
72        return new Date($ts);
73    }
74
75
76    /**
77     * @deprecated use core.getWikiVersion instead
78     */
79    public function legacyGetVersion()
80    {
81        return getVersion();
82    }
83
84    /**
85     * @deprecated use core.getWikiTime instead
86     */
87    public function legacyGetTime()
88    {
89        return $this->getWikiTime();
90    }
91
92
93    /**
94     * @deprecated use core.getPage instead
95     */
96    public function legacyGetPage($id)
97    {
98        try {
99            return $this->getPage($id);
100        } catch (RemoteException $e) {
101            if ($e->getCode() === 121) {
102                return '';
103            }
104            throw $e;
105        }
106    }
107
108    /**
109     * @deprecated use core.getPage instead
110     */
111    public function legacyGetPageVersion($id, $rev = '')
112    {
113        try {
114            return $this->getPage($id, $rev);
115        } catch (RemoteException $e) {
116            if ($e->getCode() === 121) {
117                return '';
118            }
119            throw $e;
120        }
121    }
122
123    /**
124     * @deprecated use core.getMedia instead
125     */
126    public function legacyGetAttachment($id)
127    {
128        return new Base64(base64_decode($this->getMedia($id)));
129    }
130
131    /**
132     * @deprecated use core.getMediaInfo instead
133     */
134    public function legacygetAttachmentInfo($id)
135    {
136        $info = $this->getMediaInfo($id);
137        return [
138            'lastModified' => $this->toDate($info->revision),
139            'size' => $info->size,
140        ];
141    }
142
143    /**
144     * @deprecated use core.getPageHTML instead
145     */
146    public function legacyGetPageHTML($id)
147    {
148        try {
149            return $this->getPageHTML($id);
150        } catch (RemoteException $e) {
151            if ($e->getCode() === 121) {
152                return '';
153            }
154            throw $e;
155        }
156    }
157
158    /**
159     * @deprecated use core.getPageHTML instead
160     */
161    public function legacyGetPageHTMLVersion($id, $rev = '')
162    {
163        try {
164            return $this->getPageHTML($id, (int)$rev);
165        } catch (RemoteException $e) {
166            if ($e->getCode() === 121) {
167                return '';
168            }
169            throw $e;
170        }
171    }
172
173    /**
174     * @deprecated use core.listPages instead
175     */
176    public function legacyGetAllPages()
177    {
178        $pages = $this->listPages('', 0);
179
180        $result = [];
181        foreach ($pages as $page) {
182            $result[] = [
183                'id' => $page->id,
184                'perms' => $page->permission,
185                'size' => $page->size,
186                'lastModified' => $this->toDate($page->revision),
187            ];
188        }
189        return $result;
190    }
191
192    /**
193     * @deprecated use core.listPages instead
194     */
195    public function legacyGetPagelist($ns, $opts = [])
196    {
197        $data = $this->listPages($ns, $opts['depth'] ?? 0, $opts['hash'] ?? false);
198        $result = [];
199
200        foreach ($data as $page) {
201            $result[] = [
202                'id' => $page->id,
203                'perms' => $page->permission,
204                'size' => $page->size,
205                'rev' => $page->revision,
206                'mtime' => $page->revision,
207                'hash' => $page->hash,
208
209            ];
210        }
211
212        return $result;
213    }
214
215    /**
216     * @deprecated use core.searchPages instead
217     */
218    public function legacySearch($query)
219    {
220        $this->searchPages($query);
221        $pages = [];
222
223        foreach ($this->searchPages($query) as $page) {
224            $pages[] = [
225                'id' => $page->id,
226                'score' => $page->score,
227                'rev' => $page->revision,
228                'lastModified' => $this->toDate($page->revision),
229                'size' => $page->size,
230                'snippet' => $page->snippet,
231                'title' => $page->title
232            ];
233        }
234
235        return $pages;
236    }
237
238    /**
239     * @deprecated use core.getWikiTitle instead
240     */
241    public function legacyGetTitle()
242    {
243        return $this->getWikiTitle();
244    }
245
246    /**
247     * @deprecated use core.listMedia instead
248     */
249    public function legacyGetAttachments($ns, $options = [])
250    {
251        $files = $this->listMedia($ns, $options['pattern'] ?? '', $options['depth'] ?? 0, $options['hash'] ?? false);
252        $result = [];
253        foreach ($files as $file) {
254            $result[] = [
255                'id' => $file->id,
256                'perms' => $file->permission,
257                'size' => $file->size,
258                'rev' => $file->revision,
259                'lastModified' => $this->toDate($file->revision),
260                'mtime' => $this->toDate($file->revision),
261                'hash' => $file->hash,
262                'file' => PhpString::basename(mediaFN($file->id)),
263                'writable' => is_writable(mediaFN($file->id)),
264                'isimg' => $file->isimage,
265
266            ];
267        }
268        return $result;
269    }
270
271    /**
272     * @deprecated use core.getPageBackLinks instead
273     */
274    public function legacyGetBackLinks($id)
275    {
276        return $this->getPageBackLinks($id);
277    }
278
279    /**
280     * @deprecated use core.getPageInfo instead
281     */
282    public function legacyGetPageInfo($id)
283    {
284        $info = $this->getPageInfo($id, 0);
285        return [
286            'name' => $info->id,
287            'lastModified' => $this->toDate($info->revision),
288            'author' => $info->author,
289            'version' => $info->revision,
290        ];
291    }
292
293    /**
294     * @deprecated use core.getPageInfo instead
295     */
296    public function legacyGetPageInfoVersion($id, $rev = '')
297    {
298        $info = $this->getPageInfo($id, $rev);
299        return [
300            'name' => $info->id,
301            'lastModified' => $this->toDate($info->revision),
302            'author' => $info->author,
303            'version' => $info->revision,
304        ];
305    }
306
307    /**
308     * @deprecated use core.savePage instead
309     */
310    public function legacyPutPage($id, $text, $params = [])
311    {
312        return $this->savePage($id, $text, $params['sum'] ?? '', $params['minor'] ?? false);
313    }
314
315    /**
316     * @deprecated use core.appendPage instead
317     */
318    public function legacyAppendPage($id, $text, $params = [])
319    {
320        $ok = $this->appendPage($id, $text, $params['summary'] ?? '', $params['minor'] ?? false);
321        if ($ok === true) {
322            return cleanID($id);
323        } else {
324            return $ok;
325        }
326    }
327
328    /**
329     * @deprecated use plugin.usermanager.createUser instead
330     */
331    public function legacyCreateUser($userStruct)
332    {
333        if (!auth_isadmin()) {
334            throw new AccessDeniedException('Only admins are allowed to create users', 114);
335        }
336
337        /** @var AuthPlugin $auth */
338        global $auth;
339
340        if (!$auth->canDo('addUser')) {
341            throw new AccessDeniedException(
342                sprintf('Authentication backend %s can\'t do addUser', $auth->getPluginName()),
343                114
344            );
345        }
346
347        $user = trim($auth->cleanUser($userStruct['user'] ?? ''));
348        $password = $userStruct['password'] ?? '';
349        $name = trim(preg_replace('/[\x00-\x1f:<>&%,;]+/', '', $userStruct['name'] ?? ''));
350        $mail = trim(preg_replace('/[\x00-\x1f:<>&%,;]+/', '', $userStruct['mail'] ?? ''));
351        $groups = $userStruct['groups'] ?? [];
352
353        $notify = (bool)$userStruct['notify'] ?? false;
354
355        if ($user === '') throw new RemoteException('empty or invalid user', 401);
356        if ($name === '') throw new RemoteException('empty or invalid user name', 402);
357        if (!mail_isvalid($mail)) throw new RemoteException('empty or invalid mail address', 403);
358
359        if ((string)$password === '') {
360            $password = auth_pwgen($user);
361        }
362
363        if (!is_array($groups) || $groups === []) {
364            $groups = null;
365        }
366
367        $ok = $auth->triggerUserMod('create', [$user, $password, $name, $mail, $groups]);
368
369        if ($ok !== false && $ok !== null) {
370            $ok = true;
371        }
372
373        if ($ok) {
374            if ($notify) {
375                auth_sendPassword($user, $password);
376            }
377        }
378
379        return $ok;
380    }
381
382
383    /**
384     * @deprecated use plugin.usermanager.deleteUser instead
385     */
386    public function legacyDeleteUsers($usernames)
387    {
388        if (!auth_isadmin()) {
389            throw new AccessDeniedException('Only admins are allowed to delete users', 114);
390        }
391        /** @var AuthPlugin $auth */
392        global $auth;
393        return (bool)$auth->triggerUserMod('delete', [$usernames]);
394    }
395
396    /**
397     * @deprecated use core.saveMedia instead
398     */
399    public function legacyPutAttachment($id, $file, $params = [])
400    {
401        $ok = $this->saveMedia($id, base64_encode($file), $params['ow'] ?? false);
402        if ($ok === true) {
403            return cleanID($id);
404        } else {
405            return $ok;
406        }
407    }
408
409    /**
410     * @deprecated use core.deleteMedia instead
411     */
412    public function legacyDeleteAttachment($id)
413    {
414        $ok = $this->deleteMedia($id);
415        if ($ok === true) {
416            return 0;
417        } else {
418            return $ok;
419        }
420    }
421
422    /**
423     * @deprecated use core.aclCheck instead
424     */
425    public function legacyAclCheck($id, $user = null, $groups = null)
426    {
427        return $this->aclCheck($id, (string)$user, (string)$groups);
428    }
429
430    /**
431     * @deprecated use core.listLinks instead
432     */
433    public function legacyListLinks($id)
434    {
435        $links = $this->getPageLinks($id);
436        $result = [];
437        foreach ($links as $link) {
438            $result[] = [
439                'type' => $link['type'],
440                'page' => $link['page'],
441                'href' => $link['href'],
442            ];
443        }
444        return $result;
445    }
446
447    /**
448     * @deprecated use core.getRecentChanges instead
449     */
450    public function legacyGetRecentChanges($timestamp)
451    {
452        $recents = $this->getRecentPageChanges($timestamp);
453        $result = [];
454        foreach ($recents as $recent) {
455            $result[] = [
456                'name' => $recent->id,
457                'lastModified' => $this->toDate($recent->revision),
458                'author' => $recent->author,
459                'version' => $recent->revision,
460                'perms' => auth_quickaclcheck($recent->id),
461                'size' => @filesize(wikiFN($recent->id)),
462            ];
463        }
464        return $result;
465    }
466
467    /**
468     * @deprecated use core.getRecentMediaChanges instead
469     */
470    public function legacyGetRecentMediaChanges($timestamp)
471    {
472        $recents = $this->getRecentMediaChanges($timestamp);
473        $result = [];
474        foreach ($recents as $recent) {
475            $result[] = [
476                'name' => $recent->id,
477                'lastModified' => $this->toDate($recent->revision),
478                'author' => $recent->author,
479                'version' => $recent->revision,
480                'perms' => auth_quickaclcheck($recent->id),
481                'size' => @filesize(mediaFN($recent->id)),
482            ];
483        }
484        return $result;
485    }
486
487    /**
488     * @deprecated use core.getPageHistory instead
489     */
490    public function legacyGetPageVersions($id, $first = 0)
491    {
492        $revisions = $this->getPageHistory($id, $first);
493        $result = [];
494
495        foreach ($revisions as $revision) {
496            $result[] = [
497                'user' => $revision->author,
498                'ip' => $revision->ip,
499                'type' => $revision->type,
500                'sum' => $revision->summary,
501                'modified' => $this->toDate($revision->revision),
502                'version' => $revision->revision,
503            ];
504        }
505        return $result;
506    }
507
508    /**
509     * @deprecated Wiki RPC spec is no longer supported
510     */
511    public function legacyGetRPCVersionSupported()
512    {
513        return 2;
514    }
515
516    /**
517     * @deprecated use core.lockPages and core.unlockPages instead
518     */
519    public function legacySetLocks($set)
520    {
521        $locked = $this->lockPages($set['lock']);
522        $lockfail = array_diff($set['lock'], $locked);
523
524        $unlocked = $this->unlockPages($set['unlock']);
525        $unlockfail = array_diff($set['unlock'], $unlocked);
526
527        return [
528            'locked' => $locked,
529            'lockfail' => $lockfail,
530            'unlocked' => $unlocked,
531            'unlockfail' => $unlockfail
532        ];
533    }
534
535    /**
536     * @deprecated use core.getAPIVersion instead
537     */
538    public function legacyGetXMLRPCAPIVersion()
539    {
540        return $this->getAPIVersion();
541    }
542
543    /**
544     * @deprecated use core.login instead
545     */
546    public function legacyLogin($user, $pass)
547    {
548        return parent::login($user, $pass);
549    }
550
551    /**
552     * @deprecated use core.logoff instead
553     */
554    public function legacyLogoff()
555    {
556        return parent::logoff();
557    }
558}
559