Subversion Repositories Applications.papyrus

Rev

Rev 1965 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
448 ddelon 1
<?php
1966 aperonnet 2
// $Id: ezmlm-threads.php,v 1.5.4.2 2008-11-05 09:55:56 aperonnet Exp $
448 ddelon 3
//
4
// ezmlm-threads.php - ezmlm-php v2.0
5
// --------------------------------------------------------------
6
// Builds, maintains & displays thread caches
7
// These cache files live in $ezmlm->tmpdir and are serialized
8
// php objects that can be unserialized and displayed easily
9
// --------------------------------------------------------------
10
 
11
require_once("ezmlm.php");
12
require_once("ezmlm-parser.php");
1336 neiluj 13
require_once ('ezmlm-langue-fr.php');
448 ddelon 14
 
15
// CLASS: ezmlm_threads will build, maintain & display thread files (even if a thread is only 1 msg)
16
class ezmlm_threads extends ezmlm_php {
17
 
18
	// load: this is the main function that should be called.
19
	// it first checks to see if the cache files are stale, if they are it calls build
20
	// other wise it loads them and calls display
21
	function load($month) {
22
		if (!is_dir($this->tempdir . "/ezmlm-php-" . $this->listname)) {
23
			$checksum = $this->tempdir . "/ezmlm-php-" . $this->listname . "-" . $month . "-" . "checksum";
24
		} else {
25
			$checksum = $this->tempdir . "/ezmlm-php-" . $this->listname . "/" . $month . "-" . "checksum";
26
		}
27
        $md5 = '' ;
28
		if (!is_file($checksum)) {
29
			$this->build($month);
30
		} else {
31
			$fd = fopen($checksum,"r");
32
			while (!preg_match('/^md5:/', $md5)) { $md5 = fgets($fd,4096); }
33
			fclose($fd);
34
			$md5 = rtrim(preg_replace('/^md5:/', '', $md5), "\n");
35
			if ($md5 != $this->md5_of_file($this->listdir . "/archive/threads/" . $month)) {
36
				print "<!-- $md5 ne " . $this->md5_of_file($this->listdir . "/archive/threads/" . $month) . " -->\n";
37
				$this->build($month);
38
			}
39
		}
1965 aperonnet 40
		return $this->display($month);
448 ddelon 41
	}
42
 
43
	// display: this loads each cache file sequentially and displays the messages in them
44
	// there is no checking of checksum's done here so load() is the preferred method to
45
	// view the threads
46
	function display($month) {
47
		$seq = 0;
48
		if (!is_dir($this->tempdir . "/ezmlm-php-" . $this->listname)) {
49
			$cache = $this->tempdir . "/ezmlm-php-" . $this->listname . "-" . $month;
50
		} else {
51
			$cache = $this->tempdir . "/ezmlm-php-" . $this->listname . "/" . $month;
52
		}
53
        // Le lien par date et par thread
1965 aperonnet 54
        $html = '[ '.$this->makelink('action=show_month&amp;actionargs[]='.$month, 'par date').' ]' ;
55
		$months = array(1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April', 5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August',
56
		9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December');
448 ddelon 57
        // remplacé par le tableau globals $mois dans ezmlm.php
1966 aperonnet 58
		$html = '<h2>'.FIL_DE_DISCUSSION.' pour '.$GLOBALS['mois'][((int)substr($month,4,2) / 1) -1] .', ' . substr($month,0,4) . '</h2>'."\n";
448 ddelon 59
 
1965 aperonnet 60
		$html = '<table class="table_cadre">'."\n";
61
		$html = '<tr><th>Num</th><th>De</th><th>Sujet</th><th>Date</th></tr>'."\n";
62
		$html = '<tr><td colspan="3"><hr /></td></tr>'."\n";
448 ddelon 63
		$ctc = 0;
64
 
65
		if (is_file($cache)) {
66
			include($cache);
67
		}
1965 aperonnet 68
		$html = '<tr><td colspan="3"></td></tr>'."\n";
69
        $html = '</table>'."\n";
448 ddelon 70
        }
71
 
72
 
73
	function thread_to_html($thread) {
74
		$html = '';
75
		$lastdepth = -1;
76
        $ctc = 0 ;
77
		$thread_curr = $thread;
78
        $class = array ('ligne_paire', 'ligne_impaire') ;
79
		while ($thread_curr != NULL) {
80
            preg_match ('!/archive/([0-9]*)/([0-9]*)!', $thread_curr->file, $match) ;
81
            if (!isset($GLOBALS['fichiers_analyses'][$match[1]][$match[2]])) {
82
                $message = file_get_contents($this->listdir . "/archive/" . $msgdir . "/" . $msgfile) ;
83
                $mimeDecode = new Mail_mimeDecode($message) ;
84
                $mailDecode = $mimeDecode->decode() ;
85
                //$msg = new ezmlm_parser();
86
                //$msg->parse_file($this->listdir . $thread_curr->file, TRUE);
87
 
88
            } else {
89
                $mailDecode = $GLOBALS['fichiers_analyses'][$match[1]][$match[2]] ;
90
            }
91
            $actionargs = preg_split("/\//", $thread_curr->file);
92
			$html .= '<tr class="'.$class[$ctc].'">'."\n";
93
			$html .= '<td>'.$actionargs[2].$actionargs[3].'</td><td>';
94
			$html .= $this->makelink('action=show_author_msgs&amp;actionargs[]='.
95
                    $this->makehash($this->decode_iso($mailDecode->headers['from'])),$this->decode_iso($this->protect_email($mailDecode->headers['from'],TRUE)));
96
			$html .= '</td>'."\n";
97
			$html .= '<td><b>';
98
			//$html .= " <a name=\"" . urlencode($thread_curr->file) . "\">";    A quoi ça sert ?
99
			for ($i = 0; $i < $thread_curr->depth; $i++) {
100
				$html .= "&nbsp;&nbsp;";
101
			}
102
			if (($this->thread_subjlen > 0) and (strlen($this->decode_iso($mailDecode->headers['subject'])) > $this->thread_subjlen)) {
103
				$subject = substr($this->decode_iso($mailDecode->headers['subject']), 0, ($this->thread_subjlen - 3 - ($thread_curr->depth * 2)));
104
				$subject = $subject . "...";
105
			} else {
106
				$subject = $this->decode_iso($mailDecode->headers['subject']);
107
			}
108
 
109
 
110
			$subject = preg_replace("/\[" . $this->listname . "\]/", "", $subject);
111
			$html .= $this->makelink("action=show_msg&amp;actionargs[]=" . $actionargs[2] . "&amp;actionargs[]=" . $actionargs[3], $subject);
112
			$html .= "</b></td>\n";
113
			$html .= '<td>' .$this->date_francaise($mailDecode->headers['date']).'</td>'."\n";
114
			$html .= "</tr>\n";
115
 
116
			$ctc++;
117
			if ($ctc == count($this->tablecolours)) { $ctc = 0; }
118
 
119
			$lastdepth = $thread_curr->depth;
120
			$thread_curr = $thread_curr->next;
121
		}
122
 
123
		$html .= '<tr><td colspan="3"><hr noshade size="1" /></td></tr>'."\n";
124
		return $html;
125
	}
126
 
127
	// build: takes one argument in the format YYYYMM and builds the thread cache file
128
	// for that month if the ezmlm thread file exists. The resulting cache file is then
129
	// stored in $this->tmpdir;
130
	function build($month) {
131
		if (!is_file($this->listdir . "/archive/threads/" . $month)) { return FALSE; }
132
 
133
		if (!is_dir($this->tempdir . "/ezmlm-php-" . $this->listname)) {
134
                        $fd2 = fopen($this->tempdir . "/ezmlm-php-" . $this->listname . "-" . $month,"w+");
135
                } else {
136
                        $fd2 = fopen($this->tempdir . "/ezmlm-php-" . $this->listname . "/" . $month,"w+");
137
                }
138
		fclose($fd2);
139
        $i=0;
140
        // ouverture du fichier thread de ezmlm
141
        // Ils sont classés mois par mois
142
		$fd1 = fopen($this->listdir . "/archive/threads/" . $month, "r");
143
		while (!feof($fd1)) {
144
			$line = fgets($fd1,4096);
145
			if (preg_match('/^[0-9]*\:[a-z]* \[.*/', $line)) {
146
				// valid ezmlm thread file entry
147
 
148
                // On place dans $subjectfile le chemin vers le fichier sujet
149
				$subjectfile = preg_replace("/^[0-9]*\:([a-z]*) \[.*/", "\\1", $line);
150
                $subjectfile = substr($subjectfile,0,2) . '/' . substr($subjectfile,2,18);
151
 
152
				$thread_head = NULL;
153
				$thread_curr = NULL;
154
				$thread_temp = NULL;
155
				$thread_depth = 1;
156
 
157
				if (!is_file($this->listdir . "/archive/subjects/" . $subjectfile)) { continue; }
158
                // on ouvre le fichier sujet
159
                // Celui-ci contient sur la première ligne le hash du sujet puis le sujet
160
                // sur les autres lignes :
161
                // num_message:annéemois:hash_auteur nom_auteur
162
				$fd2 = fopen($this->listdir . "/archive/subjects/" . $subjectfile, "r");
163
				while (!feof($fd2)) {
164
					$line2 = fgets($fd2,4096);
165
					if (preg_match('/^[0-9]/',$line2)) {
166
						$msgnum = preg_replace('/^([0-9]*):.*/', '\\1', $line2);
167
						$msgfile = $msgnum % 100;
168
                        $msgdir  = (int)($msgnum / 100);
169
						if ($msgfile < 10) { $msgfile = "0" . $msgfile; }
170
						//$msg = new ezmlm_parser();
171
						//$msg->parse_file_headers($this->listdir . "/archive/" . $msgdir . "/" . $msgfile, TRUE);
172
 
173
                        $message = file_get_contents($this->listdir . "/archive/" . $msgdir . "/" . $msgfile) ;
174
                        $mimeDecode = new Mail_mimeDecode($message) ;
175
                        $mailDecode = $mimeDecode->decode() ;
176
 
177
 
178
 
1336 neiluj 179
                        // On stocke le fichier analysée pour réutilisation ultàrieure
448 ddelon 180
                        $GLOBALS['fichiers_analyses'][$msgdir][$msgfile] =  $mailDecode ;
181
						$msgid = (isset ($mailDecode->headers['message-id']) ? $mailDecode->headers['message-id'] : '');
182
						$inreply = (isset($mailDecode->headers['in-reply-to']) ? $mailDecode->headers['in-reply-to'] : '');
183
						$references = (isset ($mailDecode->headers['references']) ? $mailDecode->headers['references'] : '') ;
184
						$thread_depth = 1;
185
 
186
						if ($thread_head == NULL) {
187
							$thread_head = new ezmlm_thread(0,'/archive/' . $msgdir . '/' . $msgfile,$msgid);
188
						} else {
189
							$thread_curr = new ezmlm_thread($depth,'/archive/' . $msgdir . '/' . $msgfile,$msgid);
190
							if ($inreply != '') { $thread_curr->inreply = $inreply; }
191
							if ($references != '') { $thread_curr->references = $references; }
192
							$thread_head->append($thread_curr);
193
						}
194
					}
195
				}
196
				fclose($fd2);
197
 
198
				// so now after all that mess $thread_head contains a full thread tree
199
				// first build the depth of each message based on 'in-reply-to' and 'references'
200
				unset($thread_temp);
201
				$thread_temp = NULL;
202
				$thread_curr =& $thread_head->next;
203
				while (get_class($thread_curr) == 'ezmlm_thread') {
204
					unset($thread_temp);
205
					$thread_temp = NULL;
206
 
207
					if ($thread_curr->inreply != '') { $thread_temp =& $thread_head->find_msgid($thread_curr->inreply); }
208
					if ($thread_temp == NULL) {
209
						if ($thread_curr->references != '') {
210
							$refs = preg_split('/ /', $thread_curr->references);
211
							$refs = array_pop($refs);
212
							$thread_temp =& $thread_head->find_msgid($refs);
213
						}
214
					}
215
					if ($thread_temp == NULL) {
216
						// we couldn't find anything... set depth to 1, the default
217
						$thread_curr->depth = 1;
218
					} else {
219
						// we found a reference, set it to it's depth + 1
220
						$thread_curr->depth = $thread_temp->depth + 1;
221
					}
222
					$thread_curr =& $thread_curr->next;
223
				}
224
 
225
				// now write it to a temp file named MONTH-SEQ where seq is cronologic sequence order of the thread.
226
				if (!is_dir($this->tempdir . "/ezmlm-php-" . $this->listname)) {
227
					@mkdir($this->tempdir . "/ezmlm-php-" . $this->listname, 0755);
228
					if (!is_dir($this->tempdir . "/ezmlm-php-" . $this->listname)) {
229
						$fd2 = fopen($this->tempdir . "/ezmlm-php-" . $this->listname . "-" . $month, "a");
230
					} else {
231
						$fd2 = fopen($this->tempdir . "/ezmlm-php-" . $this->listname . "/" . $month, "a");
232
					}
233
				} else {
234
					$fd2 = fopen($this->tempdir . "/ezmlm-php-" . $this->listname . "/" . $month, "a");
235
				}
236
				fputs($fd2,$this->thread_to_html($thread_head));
237
				fclose($fd2);
238
			}
239
		}
240
 
241
		// finally store our checksum
242
		if (!is_dir($this->tempdir . "/ezmlm-php-" . $this->listname)) {
243
			$fd2 = fopen($this->tempdir . "/ezmlm-php-" . $this->listname . "-" . $month . "-" . "checksum","w+");
244
		} else {
245
			$fd2 = fopen($this->tempdir . "/ezmlm-php-" . $this->listname . "/" . $month . "-" . "checksum","w+");
246
		}
247
		fputs($fd2,"md5:" . $this->md5_of_file($this->listdir . "/archive/threads/" . $month) . "\n");
248
		fclose($fd2);
249
		fclose($fd1);
250
 
251
		return TRUE;
252
	}
253
 
254
	// listmessages: prints out a nice little calendar and displays the message
255
	// totals for each month. The link jumps to the thread listing.
1965 aperonnet 256
    // On lit le repetoire archive/threads/ qui contient un fichier par moi avec tous les thread, par sujet
257
    // Presentes comme suit
448 ddelon 258
    // num_thread:hash [taille_du_thread] Sujet du thread (le dernier)
1965 aperonnet 259
    // les messages sont ranges par leur numero
448 ddelon 260
	function listmessages() {
261
        if (!is_dir($this->listdir . "/archive/threads/")) {
262
            return false ;
263
        }
1965 aperonnet 264
 
265
        $res = '<table id="petit_calendrier">'."\n";
266
        $res .= " <tr>\n";
267
		$res .= "  <td></td>" ;
268
        foreach ($GLOBALS['mois'] as $valeur) $res .= '<th>'.$valeur.'</th>' ;
269
		$res .=" </tr>\n";
270
        $res .= $this->calendrierMessage();
271
        $res .= "</table>\n";
272
        return $res;
273
        /*
1336 neiluj 274
        $threadcount = array();
275
 
276
		$repertoire_archive = opendir($this->listdir . "/archive/");
1965 aperonnet 277
		$tableau_annee = array();
1336 neiluj 278
		while (false !== ($item = readdir($repertoire_archive))) {
279
			// $item contient les noms des repertoires
280
			// on ne garde que ceux qui sont des chiffres
281
 
282
			if (preg_match('/[0-9]+/', $item)) {
283
				// on ouvre le fichier d index de chaque repertoire
284
				$fichier_index = fopen($this->listdir.'/archive/'.$item.'/index', 'r');
285
				$compteur = 0 ;
286
 
287
				while (!feof($fichier_index)) {
288
					// On ignore la premiere ligne
289
					$temp = fgets($fichier_index, 4096);
290
					// dans la seconde on recupere la date
291
					$temp = fgets($fichier_index, 4096);
292
					preg_match('/\t([0-9]+) ([a-zA-Z][a-zA-Z][a-zA-Z]) ([0-9][0-9][0-9][0-9])/', $temp, $match) ;
293
					if ($match[0] != '') {
1965 aperonnet 294
 
1336 neiluj 295
						$threadmonth = date('n', strtotime($match[0]))  ;
296
						$threadyear = date('Y', strtotime($match[0])) ;
297
						$threadcount[$threadyear][$threadmonth]++;
1965 aperonnet 298
						if (!in_array($threadyear, $tableau_annee)) array_push ($tableau_annee, $threadyear);
1336 neiluj 299
					}
448 ddelon 300
				}
1336 neiluj 301
				fclose ($fichier_index);
448 ddelon 302
			}
303
		}
1965 aperonnet 304
		if (count($threadcount) == 0) return 'Il n\y a pas de messages dans les archives';
305
        // La partie qui suit, simple, cree la table avec le nombre de message echange chaque mois
551 alexandre_ 306
		$res = '<table id="petit_calendrier">'."\n";
448 ddelon 307
		$res .= " <tr>\n";
308
		$res .= "  <td></td>" ;
1965 aperonnet 309
        foreach ($GLOBALS['mois'] as $valeur) $res .= '<th>'.$valeur.'</th>' ;
448 ddelon 310
		$res .=" </tr>\n";
1965 aperonnet 311
		arsort($tableau_annee);
312
		foreach ($tableau_annee as $annee) {
448 ddelon 313
			$res .= " <tr>\n";
1965 aperonnet 314
			$res .= '  <td class="col_annee">'.$annee.'</td>';
448 ddelon 315
			for ($i = 1; $i <= 12; $i++) {
1965 aperonnet 316
				$res .= '<td class="mois">';
317
				if (isset($threadcount[$annee][$i]) && $threadcount[$annee][$i] > 0) {
318
                    $res .= $this->makelink('action=show_month&amp;actionargs[]='.$annee.($i < 10 ? '0'.$i:$i),$threadcount[$annee][$i]);
319
				}
320
				$res .= '</td>';
448 ddelon 321
			}
1965 aperonnet 322
			$res .= '</tr>'."\n";
448 ddelon 323
		}
324
		$res .= "</table>\n";
1965 aperonnet 325
        return $res ;
326
        */
448 ddelon 327
	}
1965 aperonnet 328
	/*
329
	 *  Cree un fichier liste.calendrierPermanent qui contient
330
	 *  le nombre de message par mois pour toutes les annees
331
	 *  depuis le debut de la liste sauf la derniere
332
	 *
333
	 */
334
	function calculeCalendrierPermanent($Annnee = '') {
335
		$numArchive = $this->getNumArchive();
336
		$dernierRepertoire = floor($numArchive / 100);
337
 
338
		$threadcount = array();
339
		$tableau_annee = array();
340
 
341
 
342
		for ($rep_courant = $dernierRepertoire; $rep_courant >= 0; $rep_courant--) {
343
			$fichier_index = file ($this->listdir.'/archive/'.$rep_courant.'/index', FILE_IGNORE_NEW_LINES);
344
 
345
			// On parcours le fichier a l envers
346
			for ($j = count($fichier_index)-1; $j >= 0; $j-=2) {
347
				preg_match('/\t([0-9]+) ([a-zA-Z][a-zA-Z][a-zA-Z]) ([0-9][0-9][0-9][0-9])/', $fichier_index[$j], $match) ;
348
				if ($match[0] != '') {
349
					$threadmonth = date('n', strtotime($match[0]))  ;
350
					$threadyear = date('Y', strtotime($match[0])) ;
351
					if ($Annnee != '') {
352
						if ($threadyear < date('Y')) {
353
							$sortir = true;
354
							break;
355
						}
356
					}  else {
357
						if ($threadyear == date('Y')) continue;
358
					}
359
					$threadcount[$threadyear][$threadmonth]++;
360
					if (!in_array($threadyear, $tableau_annee)) array_push ($tableau_annee, $threadyear);
361
				}
362
			}
363
			if ($sortir) break;
364
		}
365
		$res = '';
366
		arsort($tableau_annee);
367
		foreach ($tableau_annee as $annee) {
368
			$res .= " <tr>\n";
369
			$res .= '  <td class="col_annee">'.$annee.'</td>';
370
			for ($i = 1; $i <= 12; $i++) {
371
				$res .= '<td class="mois">';
372
				if (isset($threadcount[$annee][$i]) && $threadcount[$annee][$i] > 0) {
373
                    $res .= $this->makelink('action=show_month&amp;actionargs[]='.$annee.($i < 10 ? '0'.$i:$i),$threadcount[$annee][$i]);
374
				}
375
				$res .= '</td>';
376
			}
377
			$res .= '</tr>'."\n";
378
		}
379
		return $res;
380
	}
381
	function ecrireFichierCalendrier() {
382
		$html = $this->calculeCalendrierPermanent();
383
		$f = fopen ('tmp/'.$this->listname.'.calendrier', 'w') ;
384
		fwrite ($f, $html);
385
		fclose($f);
386
		return $html;
387
	}
388
 
389
	function calendrierMessage() {
390
		$html = '';
391
		// On ajoute la derniere annee
392
		$html .= $this->calculeCalendrierPermanent(date ('Y'));
393
 
394
		if ($this->isFichierCalendrierExiste()) {
395
			// S il existe mais qu il est trop vieux, il faut le recalculer
396
			if ($this->isDoitRecalculerCalendrier()) {
397
				$annees = $this->getAnneesARecalculer();
398
				$html .= $this->calculeCalendrierPermanent($annees);
399
		    }
400
			$html .= file_get_contents('tmp/'.$this->listname.'.calendrier');
401
		} else {
402
			$html .= $this->ecrireFichierCalendrier();
403
		}
404
		return $html;
405
	}
406
 
407
	function isFichierCalendrierExiste() {
408
		if (file_exists('tmp/'.$this->listname.'.calendrier')) {
409
			return true;
410
		}
411
		return false;
412
	}
413
	function isDoitRecalculerCalendrier() {
414
 
415
		if (date ('Y', fileatime('tmp/'.$this->listname.'.calendrier')) != date('Y')) return true;
416
		return false;
417
	}
418
 
419
	function getAnneesARecalculer() {
420
		// On suppose que l index de ezmlm est correct
421
		$anneeFichierCalendrier = date ('Y', fileatime('tmp/'.$this->listname.'.calendrier'));
422
		return $anneeFichierCalendrier + 1;
423
	}
424
 
448 ddelon 425
}
426
 
427
// CLASS: ezmlm-thread is a quick little class to allow us to define
428
// a structure of the current thread in a single-linked list.
429
// it's a little messy since php doesn't support pointers like C does
430
// so we have to use references and a head object to append to the list.
431
class ezmlm_thread {
432
	var $next;
433
	var $depth;
434
	var $file;
435
	var $msgid;
436
	var $inreply;
437
	var $references;
438
	function append($thread) {
439
		$thread_curr =& $this;
440
		while ($thread_curr->next != NULL) {
441
			$thread_curr =& $thread_curr->next;
442
		}
443
		$thread_curr->next = $thread;
444
	}
445
	function &find_msgid($msgid) {
446
		$thread_curr =& $this;
447
		while ($thread_curr->next != NULL) {
448
			if (trim($thread_curr->msgid) == trim($msgid)) { return $thread_curr; }
449
			$thread_curr =& $thread_curr->next;
450
		}
451
		return NULL;
452
	}
453
	function ezmlm_thread($depth,$file,$msgid) {
454
		$this->depth = $depth;
455
		$this->file  = $file;
456
		$this->msgid = $msgid;
457
		$this->next = NULL;
458
	}
459
}
460
?>