1<?php
2/**
3 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
4 * @author     Michael Klier <chi@chimeric.de>
5 */
6// must be run within Dokuwiki
7if(!defined('DOKU_INC')) die();
8
9/**
10 * Class helper_plugin_blogtng_comments
11 */
12class helper_plugin_blogtng_comments extends DokuWiki_Plugin {
13
14    /**
15     * @var helper_plugin_blogtng_sqlite
16     */
17    private $sqlitehelper = null;
18
19    private $pid;
20
21    /**
22     * Constructor, loads the sqlite helper plugin
23     */
24    public function __construct() {
25        $this->sqlitehelper = plugin_load('helper', 'blogtng_sqlite');
26    }
27
28    /**
29     * Set pid
30     *
31     * @param $pid
32     */
33    public function setPid($pid) {
34        $this->pid = trim($pid);
35    }
36
37    /**
38     * Select comment by cid and return it as a blogtng_comment. The
39     * function returns false if the database query fails. It returns
40     * null if the query result is empty.
41     *
42     * @param  $cid The cid
43     * @return blogtng_comment|bool|null
44     */
45    public function comment_by_cid($cid) {
46
47        $query = 'SELECT cid, pid, source, name, mail, web, avatar, created, text, status FROM comments WHERE cid = ?';
48        $resid = $this->sqlitehelper->getDB()->query($query, $cid);
49        if ($resid === false) {
50            return false;
51        }
52        if ($this->sqlitehelper->getDB()->res2count($resid) == 0) {
53            return null;
54        }
55        $result = $this->sqlitehelper->getDB()->res2arr($resid);
56
57        $comment = new blogtng_comment();
58        $comment->init($result[0]);
59        return $comment;
60    }
61
62    /**
63     * Get comment count
64     *
65     * @param null $types
66     * @param bool $includehidden
67     * @return int
68     */
69    public function get_count($types=null, $includehidden=false) {
70        if (!$this->sqlitehelper->ready()) return 0;
71
72        $sql = 'SELECT COUNT(pid) as val
73                  FROM comments
74                 WHERE pid = ?';
75        if ($includehidden === false){
76            $sql .= ' AND status = \'visible\'';
77        }
78        $args = array();
79        $args[] = $this->pid;
80        if(is_array($types)){
81            $qs = array();
82            foreach($types as $type){
83                $args[] = $type;
84                $qs[]   = '?';
85            }
86            $sql .= ' AND type IN ('.join(',',$qs).')';
87        }
88        $res = $this->sqlitehelper->getDB()->query($sql,$args);
89        $res = $this->sqlitehelper->getDB()->res2row($res,0);
90        return (int) $res['val'];
91    }
92
93    /**
94     * Save comment
95     *
96     * @param $comment
97     */
98    public function save($comment) {
99        if (!$this->sqlitehelper->ready()) {
100            msg('BlogTNG: no sqlite helper plugin available', -1);
101            return;
102        }
103
104        if (isset($comment['cid'])) {
105            // Doing an update
106            $query = 'UPDATE comments SET pid=?, source=?, name=?, mail=?, ' .
107                     'web=?, avatar=?, created=?, text=?, status=? WHERE cid=?';
108            $this->sqlitehelper->getDB()->query($query,
109                $comment['pid'],
110                $comment['source'],
111                $comment['name'],
112                $comment['mail'],
113                $comment['web'],
114                $comment['avatar'],
115                $comment['created'],
116                $comment['text'],
117                $comment['status'],
118                $comment['cid']
119            );
120            return;
121        }
122
123        // Doing an insert
124        /** @var helper_plugin_blogtng_entry $entry */
125        $entry = plugin_load('helper', 'blogtng_entry');
126        $entry->load_by_pid($comment['pid']);
127        if ($entry->entry['commentstatus'] !== 'enabled') {
128            return;
129        }
130
131        $query =
132            'INSERT OR IGNORE INTO comments (
133                pid, source, name, mail, web, avatar, created, text, status, ip
134            ) VALUES (
135                ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
136            )';
137        $comment['status']  = ($this->getconf('moderate_comments')) ? 'hidden' : 'visible';
138
139        if(!isset($comment['created'])) $comment['created'] = time();
140
141        $comment['avatar']  = ''; // FIXME create avatar using a helper function
142
143        $this->sqlitehelper->getDB()->query($query,
144            $comment['pid'],
145            $comment['source'],
146            $comment['name'],
147            $comment['mail'],
148            $comment['web'],
149            $comment['avatar'],
150            $comment['created'],
151            $comment['text'],
152            $comment['status'],
153            $comment['ip']
154        );
155
156        //retrieve cid of this comment
157        $sql = "SELECT cid
158                  FROM comments
159                 WHERE pid = ?
160                   AND created = ?
161                   AND mail =?
162                 LIMIT 1";
163        $res = $this->sqlitehelper->getDB()->query($sql,
164                                                   $comment['pid'],
165                                                   $comment['created'],
166                                                   $comment['mail']);
167        $cid = $this->sqlitehelper->getDB()->res2single($res);
168        $comment['cid'] = $cid === false ? 0 : $cid;
169
170
171        // handle subscriptions
172        if($this->getConf('comments_subscription')) {
173            if($comment['subscribe']) {
174                $this->subscribe($comment['pid'],$comment['mail']);
175            }
176            // send subscriber and notify mails
177            $this->send_subscriber_mails($comment);
178        }
179    }
180
181    /**
182     * Delete comment
183     *
184     * @param $cid
185     * @return bool
186     */
187    public function delete($cid) {
188        if (!$this->sqlitehelper->ready()) return false;
189        $query = 'DELETE FROM comments WHERE cid = ?';
190        return (bool) $this->sqlitehelper->getDB()->query($query, $cid);
191    }
192
193    /**
194     * Delete all comments for an entry
195     *
196     * @param $pid
197     * @return bool
198     */
199    public function delete_all($pid) {
200        if (!$this->sqlitehelper->ready()) return false;
201        $sql = "DELETE FROM comments WHERE pid = ?";
202        return (bool) $this->sqlitehelper->getDB()->query($sql,$pid);
203    }
204
205    /**
206     * Moderate comment
207     *
208     * @param $cid
209     * @param $status
210     * @return bool
211     */
212    public function moderate($cid, $status) {
213        if (!$this->sqlitehelper->ready()) return false;
214        $query = 'UPDATE comments SET status = ? WHERE cid = ?';
215        return (bool) $this->sqlitehelper->getDB()->query($query, $status, $cid);
216    }
217
218    /**
219     * Send a mail about the new comment
220     *
221     * Mails are sent to the author of the post and
222     * all subscribers that opted-in
223     *
224     * @param $comment
225     */
226    public function send_subscriber_mails($comment){
227        global $conf;
228
229        if (!$this->sqlitehelper->ready()) return;
230
231        // get general article info
232        $sql = "SELECT title, page, mail
233                  FROM entries
234                 WHERE pid = ?";
235        $res = $this->sqlitehelper->getDB()->query($sql,$comment['pid']);
236        $entry = $this->sqlitehelper->getDB()->res2row($res,0);
237
238        // prepare mail bodies
239        $atext = io_readFile($this->localFN('notifymail'));
240        $stext = io_readFile($this->localFN('subscribermail'));
241        $title = sprintf($this->getLang('subscr_subject'),$entry['title']);
242
243        $repl = array(
244            '@TITLE@'       => $entry['title'],
245            '@NAME@'        => $comment['name'],
246            '@COMMENT@'     => $comment['text'],
247            '@USER@'        => $comment['name'],
248            '@MAIL@'        => $comment['mail'],
249            '@DATE@'        => dformat(time()),
250            '@BROWSER@'     => $_SERVER['HTTP_USER_AGENT'],
251            '@IPADDRESS@'   => clientIP(),
252            '@HOSTNAME@'    => gethostsbyaddrs(clientIP()),
253            '@URL@'         => wl($entry['page'],'',true).($comment['cid'] ? '#comment_'.$comment['cid'] : ''),
254            '@DOKUWIKIURL@' => DOKU_URL,
255        );
256
257        $atext = str_replace(array_keys($repl),array_values($repl),$atext);
258        $stext = str_replace(array_keys($repl),array_values($repl),$stext);
259
260        // notify author
261        $mails = array_map('trim', explode(',', $conf['notify']));
262        $mails[] = $entry['mail'];
263        $mails = array_unique(array_filter($mails));
264        if (count($mails) > 0) {
265            mail_send('', $title, $atext, $conf['mailfrom'], '', implode(',', $mails));
266        }
267
268        // finish here when subscriptions disabled
269        if(!$this->getConf('comments_subscription')) return;
270
271        // get subscribers
272        $sql = "SELECT A.mail as mail, B.key as key
273                  FROM subscriptions A, optin B
274                 WHERE A.mail = B.mail
275                   AND B.optin = 1
276                   AND A.pid = ?";
277        $res = $this->sqlitehelper->getDB()->query($sql,$comment['pid']);
278        $rows = $this->sqlitehelper->getDB()->res2arr($res);
279        foreach($rows as $row){
280            // ignore commenter herself:
281            if($row['mail'] == $comment['mail']) continue;
282            // ignore email addresses already notified:
283            if(in_array($row['mail'], $mails)) continue;
284            mail_send($row['mail'], $title, str_replace('@UNSUBSCRIBE@', wl($entry['page'],array('btngu'=>$row['key']),true), $stext), $conf['mailfrom']);
285        }
286    }
287
288    /**
289     * Send a mail to commenter and let her login
290     *
291     * @param $mail
292     * @param $key
293     */
294    public function send_optin_mail($mail,$key){
295        global $conf;
296
297        $text  = io_readFile($this->localFN('optinmail'));
298        $title = sprintf($this->getLang('optin_subject'));
299
300        $repl = array(
301            '@TITLE@'       => $conf['title'],
302            '@URL@'         => wl('',array('btngo'=>$key),true),
303            '@DOKUWIKIURL@' => DOKU_URL,
304        );
305        $text = str_replace(array_keys($repl),array_values($repl),$text);
306
307        mail_send($mail, $title, $text, $conf['mailfrom']);
308    }
309
310    /**
311     * Subscribe entry
312     *
313     * @param string $pid  - entry to subscribe
314     * @param string $mail - email of subscriber
315     * @param int $optin - set to 1 for immediate optin
316     */
317    public function subscribe($pid, $mail, $optin = -3) {
318        if (!$this->sqlitehelper->ready()) {
319            msg('BlogTNG: subscribe fails. (sqlite helper plugin not available)',-1);
320            return;
321        }
322
323        // add to subscription list
324        $sql = "INSERT OR IGNORE INTO subscriptions
325                      (pid, mail) VALUES (?,?)";
326        $this->sqlitehelper->getDB()->query($sql,$pid,strtolower($mail));
327
328        // add to optin list
329        if($optin == 1){
330            $sql = "INSERT OR REPLACE INTO optin
331                          (mail,optin,key) VALUES (?,?,?)";
332            $this->sqlitehelper->getDB()->query($sql,strtolower($mail),$optin,md5(time()));
333        }else{
334            $sql = "INSERT OR IGNORE INTO optin
335                          (mail,optin,key) VALUES (?,?,?)";
336            $this->sqlitehelper->getDB()->query($sql,strtolower($mail),$optin,md5(time()));
337
338            // see if we need to send a optin mail
339            $sql = "SELECT optin, key FROM optin WHERE mail = ?";
340            $res = $this->sqlitehelper->getDB()->query($sql,strtolower($mail));
341            $row = $this->sqlitehelper->getDB()->res2row($res,0);
342            if($row['optin'] < 0){
343                $this->send_optin_mail($mail,$row['key']);
344                $sql = "UPDATE optin SET optin = optin+1 WHERE mail = ?";
345                $this->sqlitehelper->getDB()->query($sql,strtolower($mail));
346            }
347        }
348
349
350    }
351
352    /**
353     * Unsubscribe by key
354     *
355     * @param $pid
356     * @param $key
357     */
358    public function unsubscribe_by_key($pid, $key) {
359        if (!$this->sqlitehelper->ready()) {
360            msg('BlogTNG: unsubscribe by key fails. (sqlite helper plugin not available)',-1);
361            return;
362        }
363        $sql = 'SELECT mail FROM optin WHERE key = ?';
364        $res = $this->sqlitehelper->getDB()->query($sql, $key);
365        $row = $this->sqlitehelper->getDB()->res2row($res);
366        if (!$row) {
367            msg($this->getLang('unsubscribe_err_key'), -1);
368            return;
369        }
370
371        $this->unsubscribe($pid, $row['mail']);
372    }
373
374    /**
375     * Unsubscribe entry
376     *
377     * @param $pid
378     * @param $mail
379     */
380    public function unsubscribe($pid, $mail) {
381        if (!$this->sqlitehelper->ready()) {
382            msg($this->getlang('unsubscribe_err_other') . ' (sqlite helper plugin not available)', -1);
383            return;
384        }
385        $sql = 'DELETE FROM subscriptions WHERE pid = ? AND mail = ?';
386        $res = $this->sqlitehelper->getDB()->query($sql, $pid, $mail);
387        $upd = $this->sqlitehelper->getDB()->countChanges($res);
388
389        if ($upd) {
390            msg($this->getLang('unsubscribe_ok'), 1);
391        } else {
392            msg($this->getlang('unsubscribe_err_other'), -1);
393        }
394    }
395
396    /**
397     * Opt in
398     *
399     * @param $key
400     */
401    public function optin($key) {
402        if (!$this->sqlitehelper->ready()) {
403            msg($this->getlang('optin_err') . ' (sqlite helper plugin not available)', -1);
404            return;
405        }
406
407        $sql = 'UPDATE optin SET optin = 1 WHERE key = ?';
408        $res = $this->sqlitehelper->getDB()->query($sql,$key);
409        $upd = $this->sqlitehelper->getDB()->countChanges($res);
410
411        if($upd){
412            msg($this->getLang('optin_ok'),1);
413        }else{
414            msg($this->getLang('optin_err'),-1);
415        }
416    }
417
418    /**
419     * Enable discussion
420     *
421     * @param $pid
422     */
423    public function enable($pid) {
424    }
425
426    /**
427     * Disable discussion
428     *
429     * @param $pid
430     */
431    public function disable($pid) {
432    }
433
434    /**
435     * Close discussion
436     *
437     * @param $pid
438     */
439    public function close($pid) {
440    }
441
442    /**
443     * Prints the comment form
444     *
445     * FIXME
446     *  allow comments only for registered users
447     *  add toolbar
448     *
449     * @param $page
450     * @param $pid
451     * @param $tplname
452     */
453    public function tpl_form($page, $pid, $tplname) {
454        global $BLOGTNG;
455
456        $form = new Doku_Form(array('id'=>'blogtng__comment_form','action'=>wl($page).'#blogtng__comment_form','data-tplname'=>$tplname));
457        $form->addHidden('pid', $pid);
458        $form->addHidden('id', $page);
459        $form->addHidden('btng[comment][source]', 'comment');
460
461        foreach(array('name', 'mail', 'web') as $field) {
462            $attr = ($BLOGTNG['comment_submit_errors'][$field]) ?  array('class' => 'edit error') : array();
463
464            if($field == 'web' && !$this->getConf('comments_allow_web')) {
465                continue;
466            } else {
467                $form->addElement(
468                        form_makeTextField(
469                        'btng[comment][' . $field . ']',
470                        $BLOGTNG['comment'][$field],
471                        $this->getLang('comment_'.$field),
472                        'blogtng__comment_' . $field,
473                        'edit block',
474                        $attr)
475                );
476            }
477        }
478
479        $form->addElement(form_makeOpenTag('div', array('class' => 'blogtng__toolbar')));
480        $form->addElement(form_makeCloseTag('div'));
481
482        if($BLOGTNG['comment_submit_errors']['text']) {
483            $form->addElement(form_makeWikiText($BLOGTNG['comment']['text'], array('class' => 'edit error')));
484        } else {
485            $form->addElement(form_makeWikiText($BLOGTNG['comment']['text']));
486        }
487
488        //add captcha if available
489        /** @var helper_plugin_captcha $helper */
490        $helper = null;
491        if(@is_dir(DOKU_PLUGIN.'captcha')) $helper = plugin_load('helper','captcha');
492        if(!is_null($helper) && $helper->isEnabled()){
493            $form->addElement($helper->getHTML());
494        }
495
496        $form->addElement(form_makeButton('submit', 'comment_preview', $this->getLang('comment_preview'), array('class' => 'button', 'id' => 'blogtng__preview_submit')));
497        $form->addElement(form_makeButton('submit', 'comment_submit', $this->getLang('comment_submit'), array('class' => 'button', 'id' => 'blogtng__comment_submit')));
498
499        if($this->getConf('comments_subscription')){
500            $form->addElement(form_makeCheckboxField('blogtng[subscribe]', 1, $this->getLang('comment_subscribe')));
501        }
502
503        print '<div id="blogtng__comment_form_wrap">'.DOKU_LF;
504        $form->printForm();
505        if(isset($BLOGTNG['comment_action']) && ($BLOGTNG['comment_action'] == 'preview') && empty($BLOGTNG['comment_submit_errors'])) {
506            print '<div id="blogtng__comment_preview">' . DOKU_LF;
507            $comment = new blogtng_comment();
508            $comment->data = $BLOGTNG['comment'];
509            $comment->data['cid'] = 'preview';
510            $comment->output($tplname);
511            print '</div>' . DOKU_LF;
512        }
513        print '</div>'.DOKU_LF;
514    }
515
516    /**
517     * Print the number of comments
518     *
519     * @param string $fmt_zero_comments - text for no comment
520     * @param string $fmt_one_comments - text for 1 comment
521     * @param string $fmt_comments - text for 1+ comment
522     * @param array  $types - a list of wanted comment sources (empty for all)
523     * @return bool
524     */
525    public function tpl_count($fmt_zero_comments='', $fmt_one_comments='', $fmt_comments='', $types=null) {
526        if(!$this->pid) return;
527
528        if(!$fmt_zero_comments)
529            $fmt_zero_comments = $this->getLang('0comments');
530        if(!$fmt_one_comments)
531            $fmt_one_comments = $this->getLang('1comments');
532        if(!$fmt_comments)
533            $fmt_comments = $this->getLang('Xcomments');
534
535        $count = $this->get_count($types);
536
537        switch($count) {
538            case 0:
539                printf($fmt_zero_comments, $count);
540                break;
541            case 1:
542                printf($fmt_one_comments, $count);
543                break;
544            default:
545                printf($fmt_comments, $count);
546                break;
547        }
548    }
549
550    /**
551     * Print the comments
552     */
553    public function tpl_comments($name,$types=null) {
554        $pid = $this->pid;
555        if(!$pid) return;
556
557        if (!$this->sqlitehelper->ready()) return;
558
559        $sql = 'SELECT *
560                  FROM comments
561                 WHERE pid = ?';
562        $args = array();
563        $args[] = $pid;
564        if(is_array($types)){
565            $qs = array();
566            foreach($types as $type){
567                $args[] = $type;
568                $qs[]   = '?';
569            }
570            $sql .= ' AND type IN ('.join(',',$qs).')';
571        }
572        $sql .= ' ORDER BY created ASC';
573        $res = $this->sqlitehelper->getDB()->query($sql,$args);
574        $res = $this->sqlitehelper->getDB()->res2arr($res);
575
576        $comment = new blogtng_comment();
577        foreach($res as $row){
578            $comment->init($row);
579            $comment->output($name);
580        }
581    }
582
583    /**
584     * Displays a list of recent comments
585     *
586     * @param $conf
587     * @return string
588     */
589    public function xhtml_recentcomments($conf){
590        ob_start();
591        if($conf['listwrap']) echo '<ul class="blogtng_recentcomments">';
592        $this->tpl_recentcomments($conf['tpl'],$conf['limit'],$conf['blog'],$conf['type']);
593        if($conf['listwrap']) echo '</ul>';
594        $output = ob_get_contents();
595        ob_end_clean();
596        return $output;
597    }
598
599    /**
600     * Display a list of recent comments
601     */
602    public function tpl_recentcomments($tpl='default',$num=5,$blogs=array('default'),$types=array()){
603        // check template
604        $tpl = helper_plugin_blogtng_tools::getTplFile($tpl, 'recentcomments');
605        if($tpl === false){
606            return false;
607        }
608
609        if(!$this->sqlitehelper->ready()) return false;
610
611        // prepare and execute query
612        if(count($types)){
613            $types  = $this->sqlitehelper->getDB()->quote_and_join($types,',');
614            $tquery = " AND B.source IN ($types) ";
615        }else{
616            $tquery = "";
617        }
618        $blog_query = '(A.blog = '.
619                       $this->sqlitehelper->getDB()->quote_and_join($blogs,
620                                                           ' OR A.blog = ').')';
621        $query = "SELECT A.pid as pid, page, title, cid
622                    FROM entries A, comments B
623                   WHERE $blog_query
624                     AND A.pid = B.pid
625                     $tquery
626                     AND B.status = 'visible'
627                     AND GETACCESSLEVEL(A.page) >= ".AUTH_READ."
628                ORDER BY B.created DESC
629                   LIMIT ".(int) $num;
630
631        $res = $this->sqlitehelper->getDB()->query($query);
632
633        if(!$this->sqlitehelper->getDB()->res2count($res)) return false; // no results found
634        $res = $this->sqlitehelper->getDB()->res2arr($res);
635
636        // print all hits using the template
637        foreach($res as $row){
638            /** @var helper_plugin_blogtng_entry $entry */
639            $entry   = plugin_load('helper', 'blogtng_entry');
640            $entry->load_by_pid($row['pid']);
641            $comment = $this->comment_by_cid($row['cid']);
642            include($tpl);
643        }
644        return true;
645    }
646
647}
648
649/**
650 * Simple wrapper class for a single comment object
651 */
652class blogtng_comment{
653    var $data;
654    var $num;
655
656    /**
657     * Resets the internal data with a given row
658     */
659    public function blogtng_comment(){
660        $this->tools = new helper_plugin_blogtng_tools();
661    }
662
663    /**
664     * @param $row array row of table 'commments'
665     */
666    public function init($row){
667        $this->data = $row;
668    }
669
670    /**
671     * Render a comment using the templates comments file.
672     *
673     * @param string $name of template
674     * @return bool
675     */
676    public function output($name){
677        global $INFO;
678        $name = preg_replace('/[^a-zA-Z_\-]+/','',$name);
679        $tpl = $this->tools->getTplFile($name,'comments');
680        if($tpl === false){
681            return false;
682        }
683
684        $comment = $this;
685        if($comment->data['status'] == 'visible' || ($comment->data['status'] == 'hidden' && $INFO['isadmin'])) {
686            $comment->num++;
687            include($tpl);
688        }
689        return true;
690    }
691
692    /**
693     * Get translated string for @$name
694     *
695     * @param   string  $name     id of the string to be retrieved
696     * @return  string  string in appropriate language or english if not available
697     */
698    public function getLang($name){
699        return $this->tools->getLang($name);
700    }
701
702    /**
703     * Render the text/content of a single comment
704     *
705     * @param   string  $name     id of the string to be retrieved
706     * @return  string  string in appropriate language or english if not available
707     */
708    public function tpl_comment(){
709        //FIXME add caching
710
711        $inst = p_get_instructions($this->data['text']);
712        echo p_render('blogtng_comment',$inst,$info);
713    }
714
715    /**
716     * Render the cid of a single comment
717     */
718    public function tpl_cid(){
719        echo $this->data['cid'];
720    }
721
722    /**
723     * Render the number of a comment.
724     *
725     * @param bool   $link  whether wrapped with link element
726     * @param string $fmt   format of number
727     * @param string $title null or alternative title
728     */
729    public function tpl_number($link = true, $fmt = '%d', $title = null) {
730        if($title === null) $title = sprintf($fmt, $this->num);
731
732        if($link) echo '<a href="#comment_' . $this->data['cid'] . '" class="blogtng_num">';
733        echo $title;
734        if($link) echo '</a>';
735    }
736
737    /**
738     * Render the hcard/userdata of a single comment
739     */
740    public function tpl_hcard(){
741        echo '<div class="vcard">';
742        if($this->data['web']){
743            echo '<a href="'.hsc($this->data['web']).'" class="fn nickname">';
744            echo hsc($this->data['name']);
745            echo '</a>';
746        }else{
747            echo '<span class="fn nickname">';
748            echo hsc($this->data['name']);
749            echo '</span>';
750        }
751        echo '</div>';
752    }
753
754    /**
755     * Render the name of a single comment
756     */
757    public function tpl_name(){
758        echo hsc($this->data['name']);
759    }
760
761    /**
762     * Render the type of a single comment
763     */
764    public function tpl_type(){
765        echo hsc($this->data['type']);
766    }
767
768    /**
769     * Render the mail of a single comment
770     */
771    public function tpl_mail(){
772        echo hsc($this->data['mail']);
773    }
774
775    /**
776     * Render the web address of a single comment
777     */
778    public function tpl_web(){
779        echo hsc($this->data['web']);
780    }
781
782    /**
783     * Render the creation date of a single comment
784     *
785     * @param string $fmt date format, empty string default to $conf['dformat']
786     */
787    public function tpl_created($fmt=''){
788        echo hsc(dformat($this->data['created'],$fmt));
789    }
790
791    /**
792     * Render the status of a single comment
793     */
794    public function tpl_status() {
795        echo $this->data['status'];
796    }
797
798    /**
799     * Render the avatar of a single comment
800     *
801     * @param int $w avatar width
802     * @param int $h avatar height
803     * @param bool $return whether the url is returned or printed
804     * @return void|string url of avatar
805     */
806    public function tpl_avatar($w=0,$h=0,$return=false){
807        global $conf;
808        $img = '';
809        if($this->data['avatar']) {
810            $img = $this->data['avatar'];
811            //FIXME add hook for additional methods
812        } elseif ($this->data['mail']) {
813            $dfl = $conf['plugin']['blogtng']['comments_gravatar_default'];
814            if(!isset($dfl) || $dfl == 'blank') $dfl = DOKU_URL . 'lib/images/blank.gif';
815
816            $img = 'http://gravatar.com/avatar.php'
817                 . '?gravatar_id=' . md5($this->data['mail'])
818                 . '&size=' . $w
819                 . '&rating=' . $conf['plugin']['blogtng']['comments_gravatar_rating']
820                 . '&default='.rawurlencode($dfl)
821                 . '&.png';
822        } elseif ($this->data['web']){
823            $img = 'http://getfavicon.appspot.com/'.rawurlencode($this->data['web']).'?.png';
824        }
825
826
827        //use fetch for caching and resizing
828        if($img){
829            $img = ml($img,array('w'=>$w,'h'=>$h,'cache'=>'recache'));
830        }
831        if($return) {
832            return $img;
833        } else {
834            print $img;
835        }
836    }
837}
838// vim:ts=4:sw=4:et:
839