1<?php
2/**
3 * Include Plugin: displays a wiki page within another
4 * Usage:
5 * {{fortune}}
6 *
7 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
8 * @author     Otto Vainio <oiv-plugins@valjakko.net>
9 */
10
11if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
13require_once(DOKU_PLUGIN.'syntax.php');
14
15/**
16 * All DokuWiki plugins to extend the parser/rendering mechanism
17 * need to inherit from this class
18 */
19class syntax_plugin_fortune extends DokuWiki_Syntax_Plugin {
20
21    /**
22     * return some info
23     */
24    function getInfo(){
25        return array(
26            'author' => 'Otto Vainio',
27            'email'  => 'oiv-plugins@valjakko.net',
28            'date'   => '2005-10-14',
29            'name'   => 'Fortune Plugin',
30            'desc'   => 'Displays qotd (Quote Of The Day)',
31            'url'    => 'http://wiki.splitbrain.org/plugin:fortune',
32        );
33    }
34
35    /**
36     * What kind of syntax are we?
37     */
38    function getType(){
39        return 'substition';
40    }
41
42    /**
43     * Where to sort in?
44     */
45    function getSort(){
46        return 56;
47    }
48
49    /**
50     * Paragraph Type
51     */
52    function getPType(){
53        return 'block';
54    }
55
56
57    /**
58     * Connect pattern to lexer
59     */
60    function connectTo($mode) {
61      $this->Lexer->addSpecialPattern("{{fortune}}",$mode,'plugin_fortune');
62    }
63
64    /**
65     * Handle the match
66     */
67    function handle($match, $state, $pos, &$handler){
68        return $match;
69    }
70
71    /**
72     * Create output
73     */
74    function render($mode, &$renderer, $data) {
75
76        if($mode == 'xhtml'){
77//           include_once "fortuneclass.php";
78            $f = new Fortune;
79            $fortunecookie = $f->quoteFromDir(DOKU_PLUGIN . "fortune/dat/");
80            $renderer->doc .= "<div class=\"fortune\">";
81            $renderer->doc .= nl2br(htmlspecialchars($fortunecookie));
82            $renderer->doc .= "</div>";
83
84            return true;
85        }
86        return false;
87    }
88}
89/*
90Main methods to use:
91 quoteFromDir($dir):
92   Quotes from any of the fortune-files in the dir.
93 getRandomQuote($file):
94   Quotes from the specific file.
95
96 Written by Henrik Aasted Sorensen, henrik@aasted.org
97 Read more at http://www.aasted.org/quote
98 Edited by Otto Vainio
99*/
100
101class Fortune {
102  function quoteFromDir($dir) {
103    $amount = 0;
104    $index = 0;
105    clearstatcache();
106    if ( $handle = opendir($dir) ) {
107      while (false !== ($file = readdir($handle))) {
108        if (strlen($file)>2 && $file!="_dummy") {
109          if (substr($file,-4) == ".dat"){
110            if (@filemtime(substr($file,0,-4))>@filemtime($dir.$file)) {
111                $this->createIndexFile($dir.substr($file,0,-4));
112            }
113            $number = $this->getNumberOfQuotes($dir . $file);
114            $amount += $number;
115            $quotes[$index] = $amount;
116            $files[$index] = $file;
117            $index++;
118          } else {
119            if (!is_file($dir.$file.".dat") || (@filemtime($dir.$file)>@filemtime($dir.$file.".dat"))) {
120                $this->createIndexFile($dir.$file);
121                $number = $this->getNumberOfQuotes($dir . $file . ".dat");
122                $amount += $number;
123                $quotes[$index] = $amount;
124                $files[$index] = $file.".dat";
125                $index++;
126            }
127          }
128        }
129      }
130      srand((double)microtime()*1000000);
131      $index = rand(0, $amount);
132      $i = 0;
133      while ($quotes[$i] < $index)  {
134        $i++;
135      }
136      return $this->getRandomQuote($dir .$files[$i]);
137    }
138    return "";
139  }
140  /*
141   Reads the number of quotes in the file.
142  */
143  function getNumberOfQuotes($file) {
144    $len=0;
145    if ($fd = @fopen($file, "rb")) {
146      $this->readLong($fd); // Just move over the first long. Might as well be fseek.
147      $len =  $this->readLong($fd);
148      fclose($fd);
149    }
150    return $len;
151  }
152  /*
153   Picks quote number $index from the dat-file in $file.
154  */
155  function getExactQuote($file, $index) {
156    if (is_file($file) == FALSE) {
157      return;
158    }
159
160    if ( ($fd = fopen($file, "rb")) == FALSE ) {
161      return;
162    }
163    fseek($fd, 24 + 4 * $index);
164
165    $phys_index = $this->readLong($fd);
166
167    fclose($fd);
168
169    $quotefile = substr($file, 0, strlen($file) - 4);
170
171    if ( ($fd = fopen($quotefile, "rb")) == FALSE ) {
172      return;
173    }
174
175    $res = $this->getQuote($fd, $phys_index);
176    fclose($fd);
177
178    return $res;
179  }
180
181  /*
182   Returns a random quote from $file.
183  */
184  function getRandomQuote($file) {
185    $number = $this->getNumberOfQuotes($file);
186
187    $index = rand(0, $number - 1);
188
189    return $this->getExactQuote($file, $index);
190  }
191
192  /*
193   Reads a quote from the specified index.
194  */
195  function getQuote($fd, $index) {
196   fseek($fd, $index);
197   $line=""; $res = "";
198   do {
199    $res = $res . $line;
200    $line = fgets($fd, 1024);
201   } while ( ($line[0] != "%") && (!feof($fd)) );
202
203   return $res;
204  }
205
206  /*
207   Gets indexes from the file pointed to by the filedescriptor $fd.
208  */
209  function getIndices($fd) {
210    fseek($fd, 24, SEEK_SET);
211    $i = 0;
212
213    while ( feof($fd) == FALSE ) {
214      $res[$i] = readLong($fd);
215      $i++;
216    }
217    return $res;
218  }
219
220  function readLong($fd) {
221    $res = fread($fd, 4);
222    $l = ord($res[3]);
223    $l += ord($res[2]) << 8;
224    $l += ord($res[1]) << 16;
225    $l += ord($res[0]) << 24;
226    return $l;
227  }
228  function createIndexFile($file) {
229    $fd = fopen($file, "r");
230    if ($fd == false) {
231//                  echo "File error!";
232      exit;
233    }
234
235    $i = 1;
236    $length = 0;
237    $longest = 0;
238    $shortest = 100000;
239    $indices[0] = 0;
240    while (!feof($fd)) {
241      $line = fgets($fd);
242      if ($line == "%\n") {
243        $indices[$i] = ftell($fd);
244        $i++;
245        if ($length > $longest)
246           $longest = $length;
247        if ($length < $shortest)
248           $shortest = $length;
249        $length = 0;
250      } else {
251        $length = $length + strlen($line);
252      }
253    }
254    fclose($fd);
255    $fd = @fopen($file . ".dat", "w");
256    if ($fd == false) {
257//                  echo "<!-- createIndexFile: Could not write to file....-->";
258      exit;
259    }
260
261    // Write header.
262    $this->writeLong($fd, 2);
263    $this->writeLong($fd, count($indices));
264    $this->writeLong($fd, $longest);
265    $this->writeLong($fd, $shortest);
266    $this->writeLong($fd, 0);
267    $this->writeLong($fd, 37 << 24);
268
269    for ($i = 0 ; $i < count($indices) ; $i++) {
270      $this->writeLong($fd, $indices[$i]);
271    }
272
273    fclose($fd);
274  }
275
276  function writeLong($fd, $l) {
277    fwrite($fd, chr ( ($l >> 24) & 255));
278    fwrite($fd, chr ( ($l >> 16) & 255));
279    fwrite($fd, chr ( ($l >> 8) & 255));
280    fwrite($fd, chr ( $l & 255));
281  }
282}// End of class
283?>