1<?php
2
3
4/**
5 * Linkback helper plugin
6 *
7 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
8 * @author     Gina Haeussge <osd@foosel.net>
9 */
10
11class helper_plugin_linkback extends DokuWiki_Plugin {
12
13    function getMethods() {
14        $result = array ();
15        $result[] = array (
16            'name' => 'th',
17            'desc' => 'returns the header of the linkback column for pagelist',
18            'return' => array (
19                'header' => 'string'
20            ),
21        );
22        $result[] = array (
23            'name' => 'td',
24            'desc' => 'returns the link to the linkback section with number of comments',
25            'params' => array (
26                'id' => 'string',
27                'number of linkbacks (optional)' => 'integer'
28            ),
29            'return' => array (
30                'link' => 'string'
31            ),
32        );
33        $result[] = array (
34            'name' => 'getLinkbacks',
35            'desc' => 'returns recently added linkbacks individually',
36            'params' => array (
37                'namespace' => 'string',
38                'number (optional)' => 'integer'
39            ),
40            'return' => array (
41                'pages' => 'array'
42            ),
43        );
44        return $result;
45    }
46
47    /**
48     * Returns the header of the linkback column for the pagelist
49     */
50    function th() {
51        return $this->getLang('linkbacks');
52    }
53
54    /**
55     * Returns the link to the linkback section with number of comments
56     */
57    function td($ID, $number = NULL) {
58        $section = '#linkback__section';
59
60        if (!isset ($number)) {
61            $lfile = metaFN($ID, '.linkbacks');
62            $linkbacks = unserialize(io_readFile($lfile, false));
63
64            if ($linkbacks){
65                $number = $linkbacks['number'];
66                if (!$linkbacks['display']) {
67                    return '';
68                }
69            } else {
70                return '';
71            }
72        }
73
74        if ($number == 0) {
75            $linkback = '0&nbsp;' . $this->getLang('linkback_plural');
76        } elseif ($number == 1) {
77            $linkback = '1&nbsp;' . $this->getLang('linkback_singular');
78        } else {
79            $linkback = $number . '&nbsp;' . $this->getLang('linkback_plural');
80        }
81
82        return '<a href="' . wl($ID) . $section . '" class="wikilink1" title="' . $ID . $section . '">' .
83        $linkback . '</a>';
84
85    }
86
87    /**
88     * Returns recently added linkbacks individually
89     */
90    function getLinkbacks($ns, $num = NULL) {
91        global $conf;
92
93        $first = $_REQUEST['first'];
94        if (!is_numeric($first)) {
95            $first = 0;
96        }
97
98        if ((!$num) || (!is_numeric($num))) {
99            $num = $conf['recent'];
100        }
101
102        $result = array ();
103        $count = 0;
104
105        if (!@ file_exists($conf['metadir'] . '/_linkbacks.changes')) {
106            return $result;
107        }
108
109        // read all recent changes. (kept short)
110        $lines = file($conf['metadir'] . '/_linkbacks.changes');
111
112        // handle lines
113        for ($i = count($lines) - 1; $i >= 0; $i--) {
114            $rec = $this->_handleRecentLinkback($lines[$i], $ns);
115            if ($rec !== false) {
116                if (-- $first >= 0) {
117                    continue;
118                } // skip first entries
119                $result[$rec['date']] = $rec;
120                $count++;
121                // break when we have enough entries
122                if ($count >= $num) {
123                    break;
124                }
125            }
126        }
127
128        // finally sort by time of last comment
129        krsort($result);
130
131        return $result;
132    }
133
134    /**
135     * Internal function used by $this->getLinkbacks()
136     *
137     * don't call directly
138     *
139     * @see getRecentComments()
140     * @author Andreas Gohr <andi@splitbrain.org>
141     * @author Ben Coburn <btcoburn@silicodon.net>
142     * @author Esther Brunner <wikidesign@gmail.com>
143     * @author Gina Haeussge <osd@foosel.net>
144     */
145    function _handleRecentLinkback($line, $ns) {
146        static $seen = array (); //caches seen pages and skip them
147        if (empty ($line)) {
148            return false; //skip empty lines
149        }
150
151        // split the line into parts
152        $recent = parseChangelogLine($line);
153        if ($recent === false) {
154            return false;
155        }
156
157        $lid = $recent['extra'];
158        $fulllid = $recent['id'] . '#' . $recent['extra'];
159
160        // skip seen ones
161        if (isset ($seen[$fulllid])) {
162            return false;
163        }
164
165        // skip 'show comment' log entries
166        if ($recent['type'] === 'sc') {
167            return false;
168        }
169
170        // remember in seen to skip additional sights
171        $seen[$fulllid] = 1;
172
173        // check if it's a hidden page or comment
174        if (isHiddenPage($recent['id'])) {
175            return false;
176        }
177        if ($recent['type'] === 'hl') {
178            return false;
179        }
180
181        // filter namespace or id
182        if (($ns) && (strpos($recent['id'] . ':', $ns . ':') !== 0)) {
183            return false;
184        }
185
186        // check ACL
187        $recent['perm'] = auth_quickaclcheck($recent['id']);
188        if ($recent['perm'] < AUTH_READ) {
189            return false;
190        }
191
192        // check existance
193        $recent['file'] = wikiFN($recent['id']);
194        $recent['exists'] = @ file_exists($recent['file']);
195        if (!$recent['exists']) {
196            return false;
197        }
198        if ($recent['type'] === 'dc') {
199            return false;
200        }
201
202        // get linkback meta file name
203        $data = unserialize(io_readFile(metaFN($recent['id'], '.linkbacks'), false));
204
205        // check if discussion is turned off
206        if (!$data['display']) {
207            return false;
208        }
209
210        // okay, then add some additional info
211        $recent['name'] = $data['receivedpings'][$lid]['url'];
212        $recent['desc'] = $data['receivedpings'][$lid]['excerpt'];
213
214        return $recent;
215    }
216
217}
218