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            $number = $linkbacks['number'];
65            if (!$linkbacks['display']) {
66                return '';
67            }
68        }
69
70        if ($number == 0) {
71            $linkback = '0&nbsp;' . $this->getLang('linkback_plural');
72        } elseif ($number == 1) {
73            $linkback = '1&nbsp;' . $this->getLang('linkback_singular');
74        } else {
75            $linkback = $number . '&nbsp;' . $this->getLang('linkback_plural');
76        }
77
78        return '<a href="' . wl($ID) . $section . '" class="wikilink1" title="' . $ID . $section . '">' .
79        $linkback . '</a>';
80
81    }
82
83    /**
84     * Returns recently added linkbacks individually
85     */
86    function getLinkbacks($ns, $num = NULL) {
87        global $conf;
88
89        $first = $_REQUEST['first'];
90        if (!is_numeric($first)) {
91            $first = 0;
92        }
93
94        if ((!$num) || (!is_numeric($num))) {
95            $num = $conf['recent'];
96        }
97
98        $result = array ();
99        $count = 0;
100
101        if (!@ file_exists($conf['metadir'] . '/_linkbacks.changes')) {
102            return $result;
103        }
104
105        // read all recent changes. (kept short)
106        $lines = file($conf['metadir'] . '/_linkbacks.changes');
107
108        // handle lines
109        for ($i = count($lines) - 1; $i >= 0; $i--) {
110            $rec = $this->_handleRecentLinkback($lines[$i], $ns);
111            if ($rec !== false) {
112                if (-- $first >= 0) {
113                    continue;
114                } // skip first entries
115                $result[$rec['date']] = $rec;
116                $count++;
117                // break when we have enough entries
118                if ($count >= $num) {
119                    break;
120                }
121            }
122        }
123
124        // finally sort by time of last comment
125        krsort($result);
126
127        return $result;
128    }
129
130    /**
131     * Internal function used by $this->getLinkbacks()
132     *
133     * don't call directly
134     *
135     * @see getRecentComments()
136     * @author Andreas Gohr <andi@splitbrain.org>
137     * @author Ben Coburn <btcoburn@silicodon.net>
138     * @author Esther Brunner <wikidesign@gmail.com>
139     * @author Gina Haeussge <osd@foosel.net>
140     */
141    function _handleRecentLinkback($line, $ns) {
142        static $seen = array (); //caches seen pages and skip them
143        if (empty ($line)) {
144            return false; //skip empty lines
145        }
146
147        // split the line into parts
148        $recent = parseChangelogLine($line);
149        if ($recent === false) {
150            return false;
151        }
152
153        $lid = $recent['extra'];
154        $fulllid = $recent['id'] . '#' . $recent['extra'];
155
156        // skip seen ones
157        if (isset ($seen[$fulllid])) {
158            return false;
159        }
160
161        // skip 'show comment' log entries
162        if ($recent['type'] === 'sc') {
163            return false;
164        }
165
166        // remember in seen to skip additional sights
167        $seen[$fulllid] = 1;
168
169        // check if it's a hidden page or comment
170        if (isHiddenPage($recent['id'])) {
171            return false;
172        }
173        if ($recent['type'] === 'hl') {
174            return false;
175        }
176
177        // filter namespace or id
178        if (($ns) && (strpos($recent['id'] . ':', $ns . ':') !== 0)) {
179            return false;
180        }
181
182        // check ACL
183        $recent['perm'] = auth_quickaclcheck($recent['id']);
184        if ($recent['perm'] < AUTH_READ) {
185            return false;
186        }
187
188        // check existance
189        $recent['file'] = wikiFN($recent['id']);
190        $recent['exists'] = @ file_exists($recent['file']);
191        if (!$recent['exists']) {
192            return false;
193        }
194        if ($recent['type'] === 'dc') {
195            return false;
196        }
197
198        // get linkback meta file name
199        $data = unserialize(io_readFile(metaFN($recent['id'], '.linkbacks'), false));
200
201        // check if discussion is turned off
202        if (!$data['display']) {
203            return false;
204        }
205
206        // okay, then add some additional info
207        $recent['name'] = $data['receivedpings'][$lid]['url'];
208        $recent['desc'] = $data['receivedpings'][$lid]['excerpt'];
209
210        return $recent;
211    }
212
213}
214