1<?php 2 3/** 4 * Display component of the DokuWiki Linkback action plugin. Highly influenced by 5 * the discussion plugin of Esther Brunner. 6 * 7 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 8 * @author Gina Haeussge <osd@foosel.net> 9 * @link http://wiki.foosel.net/snippets/dokuwiki/linkback 10 */ 11 12// must be run within Dokuwiki 13if (!defined('DOKU_INC')) 14 die(); 15 16if (!defined('DOKU_PLUGIN')) 17 define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/'); 18require_once (DOKU_PLUGIN . 'action.php'); 19 20require_once (DOKU_INC . 'inc/common.php'); 21require_once (DOKU_INC . 'inc/events.php'); 22require_once (DOKU_PLUGIN . 'linkback/tools.php'); 23 24if (!defined('NL')) 25 define('NL', "\n"); 26 27class action_plugin_linkback_display extends DokuWiki_Action_Plugin { 28 29 /** 30 * A little helper. 31 */ 32 var $tools; 33 34 /** 35 * Constructor 36 */ 37 function __construct() { 38 $this->tools =& plugin_load('tools', 'linkback'); 39 } 40 41 /** 42 * Register the eventhandlers. 43 */ 44 function register(Doku_Event_Handler $controller) { 45 $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'handle_act_render', array ()); 46 $controller->register_hook('RENDERER_CONTENT_POSTPROCESS', 'AFTER', $this, 'handle_content_postprocess', array ()); 47 } 48 49 /** 50 * Handler for the TPL_ACT_RENDER event 51 */ 52 function handle_act_render(Doku_Event $event, $params) { 53 global $ID, $INFO; 54 55 if ($event->data != 'show') 56 return; 57 58 $file = metaFN($ID, '.linkbacks'); 59 $data = array ( 60 'send' => false, 61 'receive' => false, 62 'display' => false, 63 'sentpings' => array (), 64 'receivedpings' => array (), 65 'number' => 0, 66 67 ); 68 69 if (@ file_exists($file)) 70 $data = unserialize(io_readFile($file, false)); 71 72 if (!isset ($_REQUEST['linkback']) || $INFO['perm'] != AUTH_ADMIN) 73 $_REQUEST['linkback'] = 'linkback_show'; 74 75 $lid = $_REQUEST['lid']; 76 if (!preg_match('![a-zA-Z0-9]!', $lid)) 77 $_REQUEST['linkback'] = 'linkback_show'; 78 79 switch ($_REQUEST['linkback']) { 80 // toggle show/hide 81 case 'linkback_toggle' : 82 $linkback = $data['receivedpings'][$lid]; 83 $data = $this->_changeLinkbackVisibilities(array($lid), !$linkback['show']); 84 break; 85 // delete linkback 86 case 'linkback_delete' : 87 $data = $this->_deleteLinkbacks(array($lid)); 88 break; 89 // report linkback as ham 90 case 'linkback_ham' : 91 $this->_markLinkbacks(array($lid), false); 92 break; 93 // report linkback as spam 94 case 'linkback_spam' : 95 $this->_markLinkbacks(array($lid), true); 96 break; 97 } 98 99 $this->_show($data); 100 } 101 102 /** 103 * Shows all linkbacks for the current page 104 */ 105 function _show($data) { 106 global $ID; 107 108 if (!$data['display']) 109 return; 110 111 if ((count($data['receivedpings']) == 0) && 112 (!$this->getConf('show_trackback_url') || !$this->getConf('enable_trackback'))) 113 return; 114 115 // section title 116 $title = $this->getLang('linkbacks'); 117 echo '<div class="linkback_wrapper">'; 118 echo '<h2><a name="linkback__section" id="linkback__section">' . $title . '</a></h2>'; 119 if ($this->getConf('show_trackback_url') && $data['receive']) { 120 echo '<div class="level2 hfeed linkback_trackbackurl">'; 121 echo $this->getLang('trackback_url'); 122 echo '<span class="linkback_trackbackurl">' . DOKU_URL . 'lib/plugins/linkback/exe/trackback.php/' . $ID . '</span>'; 123 echo '</div>'; 124 } 125 echo '<div class="level2 hfeed">'; 126 127 // now display the comments 128 if (isset ($data['receivedpings'])) { 129 foreach ($data['receivedpings'] as $key => $ping) { 130 $this->_print($key, $ping); 131 } 132 } 133 134 echo '</div>'; // level2 135 echo '</div>'; // comment_wrapper 136 137 return true; 138 } 139 140 /** 141 * Prints an individual linkback 142 */ 143 function _print($lid, $linkback, $visible = true) { 144 global $ID; 145 global $INFO; 146 global $conf; 147 148 if (!is_array($linkback)) 149 return false; // corrupt datatype 150 151 if (!$linkback['show']) { // linkback hidden 152 if ($INFO['perm'] == AUTH_ADMIN) 153 echo '<div class="linkback_hidden">' . NL; 154 else 155 return true; 156 } 157 158 $title = $linkback['title']; 159 $url = $linkback['url']; 160 $date = $linkback['received']; 161 $excerpt = $linkback['excerpt']; 162 $icon = $linkback['favicon']; 163 $type = $linkback['type']; 164 165 // linkback head with date and link 166 echo '<div class="hentry"><div class="linkback_head">' . NL . 167 '<a name="linkback__' . $lid . '" id="linkback__' . $lid . '"></a>' . NL . 168 '<span class="sender">'; 169 170 // show favicon image 171 if ($this->getConf('usefavicon')) { 172 if (!$icon) 173 $icon = $this->getConf('favicon_default'); 174 175 $size = 16; 176 $src = ml($icon); 177 echo '<img src="' . $src . '" class="medialeft photo" title="' . $url . '"' . 178 ' width="' . $size . '" height="' . $size . '" />' . NL; 179 $style = ' style="margin-left: ' . ($size +14) . 'px;"'; 180 } else { 181 $style = ' style="margin-left: 20px;"'; 182 } 183 184 echo $this->external_link($url, ($linkback['blog_title'] ? $linkback['blog_title'] . ': ' : '') . $title, 'urlextern url fn'); 185 echo '</span>, <abbr class="received" title="' . gmdate('Y-m-d\TH:i:s\Z', $date) . 186 '">' . strftime($conf['dformat'], $date) . '</abbr>'; 187 echo ' (<abbr class="type" title="' . $this->getLang('linkback_type_' . $type) . '">' . $this->getLang('linkback_type_' . $type) . '</abbr>)'; 188 echo NL . '</div>' . NL; // class="linkback_head" 189 190 // main linkback content 191 if (strlen($excerpt) > 0) { 192 echo '<div class="linkback_body entry-content"' . 193 ($this->getConf('usefavicon') ? $style : '') . '>' . NL . 194 $excerpt . NL . '</div>' . NL; // class="linkback_body" 195 } 196 echo '</div>' . NL; // class="hentry" 197 198 echo '<div class="linkback_buttons">' . NL; 199 if ($INFO['perm'] == AUTH_ADMIN) { 200 if (!$linkback['show']) 201 $label = $this->getLang('btn_show'); 202 else 203 $label = $this->getLang('btn_hide'); 204 205 $this->_button($lid, $label, 'linkback_toggle'); 206 $this->_button($lid, $this->getLang('btn_ham'), 'linkback_ham'); 207 $this->_button($lid, $this->getLang('btn_spam'), 'linkback_spam'); 208 $this->_button($lid, $this->getLang('btn_delete'), 'linkback_delete'); 209 } 210 echo '</div>'; 211 212 echo '<div class="linkback_line" ' . ($this->getConf('usefavicon') ? $style : '') . '> </div>' . NL; 213 214 if (!$linkback['show']) 215 echo '</div>' . NL; // class="linkback_hidden" 216 } 217 218 /** 219 * General button function. 220 * 221 * Code mostly taken from the discussion plugin by Esther Brunner. 222 */ 223 function _button($lid, $label, $act) { 224 global $ID; 225?> 226 <form class="button" method="post" action="<?php echo script() ?>"> 227 <div class="no"> 228 <input type="hidden" name="id" value="<?php echo $ID ?>" /> 229 <input type="hidden" name="do" value="show" /> 230 <input type="hidden" name="linkback" value="<?php echo $act ?>" /> 231 <input type="hidden" name="lid" value="<?php echo $lid ?>" /> 232 <input type="submit" value="<?php echo $label ?>" class="button" title="<?php echo $label ?>" /> 233 </div> 234 </form> 235 <?php 236 237 238 return true; 239 } 240 241 /** 242 * Adds a TOC entry for the linkback section. 243 * 244 * Code mostly taken from the discussion plugin by Esther Brunner. 245 */ 246 function handle_content_postprocess(Doku_Event $event, $params) { 247 global $ID; 248 global $conf; 249 250 if ($event->data[0] != 'xhtml') 251 return; // nothing to do for us 252 253 $file = metaFN($ID, '.linkbacks'); 254 if (!@ file_exists($file)) 255 return false; 256 $data = unserialize(io_readFile($file, false)); 257 if (!$data['display'] || (count($data['receivedpings']) == 0)) 258 return; // no linkback section 259 260 $pattern = '/<div id="toc__inside">(.*?)<\/div>\s<\/div>/s'; 261 if (!preg_match($pattern, $event->data[1], $match)) 262 return; // no TOC on this page 263 264 $title = $this->getLang('linkbacks'); 265 $section = '#linkback__section'; 266 $level = 3 - $conf['toptoclevel']; 267 268 $item = '<li class="level' . $level . '"><div class="li"><span class="li"><a href="' . 269 $section . '" class="toc">' . $title . '</a></span></div></li>'; 270 271 if ($level == 1) 272 $search = "</ul>\n</div>"; 273 else 274 $search = "</ul>\n</li></ul>\n</div>"; 275 276 $new = str_replace($search, $item . $search, $match[0]); 277 $event->data[1] = preg_replace($pattern, $new, $event->data[1]); 278 } 279 280 function _changeLinkbackVisibilities($lids, $visible) { 281 global $ID; 282 283 $file = metaFN($ID, '.linkbacks'); 284 $data = array ( 285 'send' => false, 286 'receive' => false, 287 'display' => false, 288 'sentpings' => array (), 289 'receivedpings' => array (), 290 'number' => 0, 291 292 ); 293 294 if (@ file_exists($file)) 295 $data = unserialize(io_readFile($file, false)); 296 $update = false; 297 298 foreach ($lids as $lid) { 299 $linkback = $data['receivedpings'][$lid]; 300 if ($linkback['show'] == $visible) 301 continue; 302 303 $linkback['show'] = $visible; 304 if ($linkback['show']) 305 $data['number']++; 306 else 307 $data['number']--; 308 $data['receivedpings'][$lid] = $linkback; 309 $this->tools->addLogEntry($linkback['received'], $ID, (($linkback['show']) ? 'sl' : 'hl'), '', $linkback['lid']); 310 $update = true; 311 } 312 313 if ($update) 314 io_saveFile($file, serialize($data)); 315 return $data; 316 } 317 318 function _deleteLinkbacks($lids) { 319 global $ID; 320 321 $file = metaFN($ID, '.linkbacks'); 322 $data = array ( 323 'send' => false, 324 'receive' => false, 325 'display' => false, 326 'sentpings' => array (), 327 'receivedpings' => array (), 328 'number' => 0, 329 330 ); 331 332 if (@ file_exists($file)) 333 $data = unserialize(io_readFile($file, false)); 334 $update = false; 335 336 foreach ($lids as $lid) { 337 $linkback = $data['receivedpings'][$lid]; 338 unset ($data['receivedpings'][$lid]); 339 if ($linkback['show']) 340 $data['number']--; 341 $this->tools->addLogEntry($linkback['received'], $ID, 'dl', '', $linkback['lid']); 342 $update = true; 343 } 344 345 if ($update) 346 io_saveFile($file, serialize($data)); 347 return $data; 348 } 349 350 function _markLinkbacks($lids, $isSpam) { 351 global $ID; 352 353 $file = metaFN($ID, '.linkbacks'); 354 $data = array ( 355 'send' => false, 356 'receive' => false, 357 'display' => false, 358 'sentpings' => array (), 359 'receivedpings' => array (), 360 'number' => 0, 361 362 ); 363 364 if (@ file_exists($file)) 365 $data = unserialize(io_readFile($file, false)); 366 367 foreach ($lids as $lid) { 368 $linkback = $data['receivedpings'][$lid]; 369 if ($isSpam) 370 trigger_event('ACTION_LINKBACK_SPAM', $linkback); 371 else 372 trigger_event('ACTION_LINKBACK_HAM', $linkback); 373 } 374 } 375 376} 377