Subversion Repositories Applications.projet

Rev

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

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