Added index in class dir to avoid unwanted directory listing. Minor
[squirrelmail.git] / class / mime.class
1 <?php
2
3 /**
4  * mime.class
5  *
6  * Copyright (c) 2002 The SquirrelMail Project Team
7  * Licensed under the GNU GPL. For full terms see the file COPYING.
8  *
9  * This contains functions needed to handle mime messages.
10  *
11  * $Id$
12  */
13
14 class msg_header {
15     /** msg_header contains generic variables for values that **/
16     /** could be in a header.                                 **/
17
18     var $type0 = '', $type1 = '', $boundary = '', $charset = '',
19         $encoding='', $size = 0, $to = array(), $from = '', $date = '',
20         $cc = array(), $bcc = array(), $reply_to = '', $subject = '',
21         $id = 0, $mailbox = '', $description = '', $filename = '',
22         $entity_id = 0, $message_id = 0, $name = '', $priority = 3, $type = '',
23         $disposition = '', $md5='', $language='',$dnt = '', $xmailer = '';
24     
25     /* 
26      * returns addres_list of supplied argument
27      * arguments: array('to', 'from', ...) or just a string like 'to'.
28      * result: string: address1, addres2, ....
29      */ 
30     
31     function setVar($var, $value) {
32         $this->{$var} = $value;
33     }
34     /* 
35     * function to get the addres strings out of the header.
36     * Arguments: string or array of strings !
37     * example1: header->getAddr_s('to').
38     * example2: header->getAddr_s(array('to','cc','bcc'))
39     */
40     function getAddr_s($arr) {
41         if (is_array($arr)) {
42             $s = '';
43             foreach($arr as $arg ) {
44                $result = $this->getAddr_s($arg);
45                if ($result) {
46                   $s .= ', ' . $result;
47                }
48             }
49             if ($s) $s = substr($s,2);
50             return $s;
51         } else {
52             $s = '';
53             eval('$addr = $this->'.$arr.';') ;
54             if (is_array($addr)) {
55                foreach ($addr as $addr_o) {
56                   if (is_object($addr_o)) {
57                      $s .= $addr_o->getAddress() . ', ';
58                   }
59                }
60                $s = substr($s,0,-2);
61             } else {
62                if (is_object($addr)) {
63                   $s .= $addr->getAddress();
64                }
65             }
66             return $s;
67         }
68     }
69     
70     function getAddr_a($arg, $excl_arr=array(), $arr = array()) {
71         if (is_array($arg)) {
72             foreach($arg as $argument ) {
73                $arr = $this->getAddr_a($argument, $excl_arr, $arr);
74             }
75             return $arr;
76         } else {
77             eval('$addr = $this->'.$arg.';') ;
78             if (is_array($addr)) {
79                foreach ($addr as $addr_o) {
80                   if (is_object($addr_o)) {
81                      if (isset($addr_o->host) && $addr_o->host !='') {
82                         $email = $addr_o->mailbox.'@'.$addr_o->host;
83                      } else {
84                         $email = $addr_o->mailbox;
85                      }
86                      $email = strtolower($email);
87                      if ($email && !isset($arr[$email]) && !isset($excl_arr[$email])) {
88                         $arr[$email] = $addr_o->personal;
89                      }
90                   }
91                }
92             } else {
93                if (is_object($addr)) {
94                   if (isset($addr->host)) {
95                      $email = $addr->mailbox.'@'.$addr->host;
96                   } else {
97                      $email = $addr->mailbox;
98                   }
99                   $email = strtolower($email);            
100                   if ($email && !isset($arr[$email]) && !isset($excl_arr[$email])) {
101                      $arr[$email] = $addr->personal;
102                   }
103                }
104             }
105             return $arr;
106         }
107     }
108 }
109
110 class address_structure {
111    var $personal = '', $adl = '', $mailbox = '', $host = '', $group = '';
112
113    function getAddress($full=true) {
114      if (is_object($this)) {
115         if (isset($this->host) && $this->host !='') {
116            $email = '<'.$this->mailbox.'@'.$this->host.'>';
117         } else {
118            $email = $this->mailbox;
119         }
120         if (trim($this->personal) !='') {
121            if ($email) {
122                 $addr = '"' . $this->personal . '" ' .$email;
123            } else {
124                 $addr = $this->personal;
125            }
126            $best_dpl = $this->personal;
127         } else {
128            $addr = $email;
129            $best_dpl = $email;
130         }
131         if ($full) {
132            return $addr;
133         } else {
134            return $best_dpl;
135         }    
136      } else return '';
137    }
138 }
139
140 class message {
141     /** message is the object that contains messages.  It is a recursive
142       object in that through the $entities variable, it can contain
143       more objects of type message.  See documentation in mime.txt for
144       a better description of how this works.
145     **/
146     var $header = '', $entities = array(), $mailbox = 'INBOX', $id = 0,
147         $envelope = '', $parent_ent, $entity, $type0='', $type1='',
148         $parent = '', $decoded_body='',
149         $is_seen = 0, $is_answered = 0, $is_deleted = 0, $is_flagged = 0,
150         $is_mdnsent = 0;
151
152     function setEnt($ent) {
153         $this->entity_id= $ent;
154     }
155     
156     function setBody($body) {
157         $this->decoded_body = $body;
158     }
159     function addEntity ($msg) {
160         $msg->parent = &$this;
161         $this->entities[] = $msg;
162     }
163
164     function addRFC822Header($read) {
165         $header = new msg_header();
166         $this->header = sqimap_parse_RFC822Header($read,$header);
167     }
168
169     function getEntity($ent) {
170         
171         $cur_ent = $this->entity_id;
172         $msg = $this;
173         if ($cur_ent == '' || $cur_ent == '0') {
174            $cur_ent_a = array();
175         } else {
176            $cur_ent_a = explode('.',$this->entity_id);
177         }
178         $ent_a = explode('.',$ent);
179         
180         $cnt = count($ent_a);
181
182         for ($i=0;$i<$cnt -1;$i++) {
183            if (isset($cur_ent_a[$i]) && $cur_ent_a[$i] != $ent_a[$i]) {
184               $msg = $msg->parent;
185               $cur_ent_a = explode('.',$msg->entity_id);
186               $i--;
187            } else if (!isset($cur_ent_a[$i])) {
188               if (isset($msg->entities[($ent_a[$i]-1)])) {
189                 $msg = $msg->entities[($ent_a[$i]-1)];
190               } else {
191                 $msg = $msg->entities[0];
192               }
193            }
194            if ($msg->type0 == 'message' && $msg->type1 == 'rfc822') { 
195               /*this is a header for a message/rfc822 entity */
196               $msg = $msg->entities[0];
197            }
198         }
199
200         if ($msg->type0 == 'message' && $msg->type1 == 'rfc822') { 
201            /*this is a header for a message/rfc822 entity */
202            $msg = $msg->entities[0];
203         }
204
205         if (isset($msg->entities[($ent_a[$cnt-1])-1])) {
206             $msg = $msg->entities[($ent_a[$cnt-1]-1)];
207         }
208
209         return $msg;
210     }
211     
212     function getMailbox() {
213       $msg = $this;
214       while (is_object($msg->parent)) {
215           $msg = $msg->parent;
216       }
217       return $msg->mailbox;
218     }
219     
220     /* 
221      * Bodystructure parser, a recursive function for generating the 
222      * entity-tree with all the mime-parts.
223      * 
224      * It follows RFC2060 and stores all the described fields in the
225      * message object. 
226      *
227      * Question/Bugs:
228      * 
229      * Ask for me (Marc Groot Koerkamp, stekkel@users.sourceforge.net.
230      *
231      */
232     function &parseStructure($read, $i=0, $message = false) {
233       $arg_no = 0;
234       $arg_a = array();
235       $cnt = strlen($read);
236       while ($i < $cnt) {
237         $char = strtoupper($read{$i});   
238         switch ($char) {
239         case '(':
240            if ($arg_no == 0 ) {
241               if (!isset($msg)) {
242                  $msg = new message();
243                  $hdr = new msg_header();
244                  $hdr->type0 = 'text';
245                  $hdr->type1 = 'plain';
246                  $hdr->encoding = 'us-ascii';
247                  
248                  if ($this->type0 == 'message' && $this->type1 == 'rfc822') {
249                     $msg->entity_id = $this->entity_id .'.0'; /* header of message/rfc822 */
250                  } else if (isset($this->entity_id) && $this->entity_id !='')  {
251                     $ent_no = count($this->entities)+1;
252                     $par_ent = substr($this->entity_id,-2);
253                     if ($par_ent{0} == '.') {
254                        $par_ent = $par_ent{1};
255                     }
256                     if ($par_ent == '0') {
257                         $ent_no = count($this->entities)+1;
258                         if ($ent_no > 0) {
259                            $ent = substr($this->entity_id,0,strrpos($this->entity_id,'.'));
260                            if ($ent) {
261                               $ent = $ent . ".$ent_no";
262                            } else {
263                               $ent = $ent_no;
264                            }
265                            $msg->entity_id = $ent;
266                         } else {
267                            $msg->entity_id = $ent_no;
268                         }   
269                     } else {
270                         $ent = $this->entity_id . ".$ent_no";
271                         $msg->entity_id = $ent;
272                     }
273                  } else { 
274                     $msg->entity_id = '0';
275                  }
276               } else {
277                    $msg->header->type0 = 'multipart';
278                    $msg->type0 = 'multipart';
279                    while ($read{$i} == '(') {
280                       $msg->addEntity($msg->parseStructure($read,&$i));
281                    }
282               }
283            } else {
284               switch ($arg_no) {
285                case 1:
286                  /* multipart properties */
287                  $i++;
288                  $arg_a[] = $this->parseProperties($read,&$i);
289                  $arg_no++;
290                  break;
291                case 2:
292                  if (isset($msg->type0) &&  $msg->type0 == 'multipart') {
293                     $i++;
294                     $arg_a[]= $msg->parseDisposition($read,&$i);
295                  } else { /* properties */
296                     /* properties */
297                     $arg_a[] = $msg->parseProperties($read,&$i);
298                  }
299                  $arg_no++;
300                  break;
301                case 3:
302                  if (isset($msg->type0) &&  $msg->type0 == 'multipart') {
303                     $i++;
304                     $arg_a[]= $msg->parseLanguage($read,&$i);
305                  }
306                case 7:
307                  if ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822') {
308
309                      $msg->header->type0 = $arg_a[0];
310                      $msg->type0 = $arg_a[0];
311
312                      $msg->header->type1 = $arg_a[1];
313                      $msg->type1 = $arg_a[1];
314                  
315                      $msg->parseEnvelope($read,&$i,&$hdr);
316                      $i++;
317                      while ($i < $cnt && $read{$i} != '(') {
318                        $i++;
319                      }
320                      $msg->addEntity($msg->parseStructure($read,&$i));
321                  }
322                  break;
323                case 8:
324                  $i++;
325                  $arg_a[] = $msg->parseDisposition($read,&$i);
326                  $arg_no++;    
327                  break;
328                case 9:
329                  if ($arg_a[0] == 'text' || 
330                        ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822')) {
331                     $i++;
332                     $arg_a[] = $msg->parseDisposition($read,&$i);
333                  } else {
334                     $i++;
335                     $arg_a[] = $msg->parseLanguage($read,&$i);
336                  }
337                  $arg_no++;    
338                  break;
339                case 10:
340                  if ($arg_a[0] == 'text' ||
341                        ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822')) {
342                     $i++;                      
343                     $arg_a[] = $msg->parseLanguage($read,&$i);
344                  }  else {
345                     $msg->parseParenthesis($read,&$i);
346                     $arg_a[] = ''; /* not yet desribed in rfc2060 */
347                  }
348                  $arg_no++;
349                  break;  
350                default:
351                  /* unknown argument, skip this part */
352                  $msg->parseParenthesis($read,&$i);
353                  $arg_a[] = '';
354                  $arg_no++;              
355                  break;
356               } /* switch */
357            }
358            break;
359         case '"':         
360            /* inside an entity -> start processing */
361            $debug = substr($read,$i,20);
362            $arg_s = $msg->parseQuote($read,&$i);
363            $arg_no++;
364            if ($arg_no < 3) $arg_s = strtolower($arg_s); /* type0 and type1 */
365            $arg_a[] = $arg_s;
366            break;
367         case 'N':
368            /* probably NIL argument */
369            if (strtoupper(substr($read,$i,4)) == 'NIL ' || 
370                strtoupper(substr($read,$i,4)) == 'NIL)') {
371               $arg_a[] = '';
372               $arg_no++;
373               $i = $i+2;
374            }      
375            break;
376         case '{':
377            /* process the literal value */
378            $arg_a[] = $msg->parseLiteral($read,&$i);
379            $arg_no++;
380            break;
381         case (is_numeric($read{$i}) ):
382            /* process integers */
383            if ($read{$i} == ' ') break; 
384            $arg_s = $read{$i};;
385            $i++;
386            while (preg_match('/\d+/',$read{$i})) { // != ' ') {
387               $arg_s .= $read{$i};
388               $i++;
389            }
390            $arg_no++;
391            $arg_a[] = $arg_s;
392            break;
393         case ')':
394            if (isset($msg->type0) && $msg->type0 == 'multipart') {
395               $multipart = true;
396            } else {
397               $multipart = false;
398            }
399            if (!$multipart) {
400               if ($arg_a[0] == 'text' ||
401                    ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822')) {
402                  $shifted_args = true;
403               } else { 
404                  $shifted_args = false;
405               }
406               $hdr->type0 = $arg_a[0];
407               $hdr->type1 = $arg_a[1];        
408
409               $msg->type0 = $arg_a[0];
410               $msg->type1 = $arg_a[1];
411
412               $arr = $arg_a[2];
413               if (is_array($arr)) {
414                  foreach($arr as $name => $value) {
415                     $hdr->{$name} = $value;
416                  }
417               }
418               $hdr->id = str_replace( '<', '', str_replace( '>', '', $arg_a[3] ) );
419               $hdr->description = $arg_a[4];
420               $hdr->encoding = strtolower($arg_a[5]);
421               $hdr->entity_id = $msg->entity_id;
422               $hdr->size = $arg_a[6];                                                 
423               if ($shifted_args) {
424                  $hdr->lines = $arg_a[7];             
425                  if (isset($arg_a[8])) {
426                     $hdr->md5 = $arg_a[8];
427                  }
428                  if (isset($arg_a[9])) {
429                     $hdr->disposition = $arg_a[9];
430                  }
431                  if (isset($arg_a[10])) {
432                     $hdr->language = $arg_a[10];
433                  }
434               } else {
435                  if (isset($arg_a[7])) {
436                     $hdr->md5 = $arg_a[7];                  
437                  }
438                  if (isset($arg_a[8])) {
439                     $hdr->disposition = $arg_a[8];
440                  }
441                  if (isset($arg_a[9])) {
442                     $hdr->language = $arg_a[9];
443                  }
444               }
445               $msg->header = $hdr;
446               $arg_no = 0;
447               $i++;
448               if (substr($msg->entity_id,-2) == '.0' && $msg->type0 !='multipart') {
449                  $msg->entity_id++;
450               }
451               return $msg;
452            } else {
453                 $hdr->type0 = 'multipart';
454                 $hdr->type1 = $arg_a[0];
455
456                 $msg->type0 = 'multipart';
457                 $msg->type1 = $arg_a[0];
458                 if (isset($arg_a[1])) {
459                    $arr = $arg_a[1];
460                    if (is_array($arr)) {
461                    foreach($arr as $name => $value) {
462                       $hdr->{$name} = $value;
463                    }
464                  }  
465                  }
466                  if (isset($arg_a[2])) {
467                     $hdr->disposition = $arg_a[2];
468                  }
469                  if (isset($arg_a[3])) {
470                     $hdr->language = $arg_a[3];
471                  }
472                  $msg->header = $hdr;
473                  return $msg;
474               }
475         default:
476            break;
477         } /* switch */
478         $i++;
479       } /* while */
480     } /* parsestructure */
481     
482     function parseProperties($read, $i) {
483       $properties = array();
484       $arg_s = '';
485       $prop_name = '';
486       while ($read{$i} != ')') {
487          if ($read{$i} == '"') {
488             $arg_s = $this->parseQuote($read,&$i);
489          } else if ($read{$i} == '{') {
490             $arg_s = $this->parseLiteral($read,&$i);
491          }
492          if ($prop_name == '' && $arg_s) {
493             $prop_name = strtolower($arg_s);     
494             $properties[$prop_name] = '';
495             $arg_s = '';            
496          } elseif ($prop_name != '' && $arg_s != '') {
497             $properties[$prop_name] = $arg_s;
498             $prop_name = '';
499             $arg_s = '';
500          }
501          $i++;
502       }
503       return $properties;
504     }
505     
506     function parseEnvelope($read, $i, $hdr) {
507         $arg_no = 0;
508         $arg_a = array();
509         $cnt = strlen($read);
510         while ($i< $cnt && $read{$i} != ')') {
511            $i++;
512            $char = strtoupper($read{$i});
513            switch ($char) {
514              case '"':
515                $arg_a[] = $this->parseQuote($read,&$i);
516                $arg_no++;
517                break;
518              case '{':
519                $arg_a[] = $this->parseLiteral($read,&$i);
520                $arg_no++;
521                break;
522              case 'N':   
523                /* probably NIL argument */
524                if (strtoupper(substr($read,$i,3)) == 'NIL') {
525                   $arg_a[] = '';
526                   $arg_no++;
527                   $i = $i+2;
528                }      
529                break;
530              case '(':
531                /* Address structure 
532                 * With group support.
533                 * Note: Group support is useless on SMTP connections
534                 * because the protocol doesn't support it
535                 */
536                $addr_a = array();
537                $group = '';
538                $a=0;
539                while ($i < $cnt && $read{$i} != ')') {
540                   if ($read{$i} == '(') {
541                      $addr = $this->parseAddress($read,&$i);
542                      if ($addr->host == '' && $addr->mailbox != '') { 
543                         /* start of group */
544                         $group = $addr->mailbox;
545                         $group_addr = $addr;
546                         $j = $a;
547                      } elseif ($group && $addr->host == '' && $addr->mailbox == '') {
548                         /* end group */
549                         if ($a == $j+1) { /* no group members */
550                            $group_addr->group = $group;
551                            $group_addr->mailbox = '';
552                            $group_addr->personal = "$group: Undisclosed recipients;";
553                            $addr_a[] = $group_addr;
554                            $group ='';
555                         }
556                      } else {
557                         $addr->group = $group;
558                         $addr_a[] = $addr;
559                      }
560                      $a++;
561                   }
562                   $i++;
563                }
564                $arg_a[] = $addr_a;
565                break;
566              default:
567                break;
568            }
569            $i++;
570         }
571         if (count($arg_a) > 9) {
572             /* argument 1: date */
573             $d = strtr($arg_a[0], array('  ' => ' '));
574             $d = explode(' ', $d);
575             $hdr->date = getTimeStamp($d);
576             /* argument 2: subject */
577             if (!trim($arg_a[1])) {
578                 $arg_a[1]= _("(no subject)");
579             }   
580             $hdr->subject = $arg_a[1];
581             /* argument 3: from */
582             $hdr->from = $arg_a[2][0];
583             /* argument 4: sender */        
584             $hdr->sender = $arg_a[3][0];
585             /* argument 5: reply-to */
586             $hdr->replyto = $arg_a[4][0];
587             /* argument 6: to */
588             $hdr->to = $arg_a[5];
589             /* argument 7: cc */
590             $hdr->cc = $arg_a[6];
591             /* argument 8: bcc */
592             $hdr->bcc = $arg_a[7];
593             /* argument 9: in-reply-to */
594             $hdr->inreplyto = $arg_a[8];
595             /* argument 10: message-id */
596             $hdr->message_id = $arg_a[9];
597         } 
598     }
599     
600     function parseLiteral($read, $i) {
601         $lit_cnt = '';
602         $i++;
603         while ($read{$i} != '}') {
604            $lit_cnt .= $read{$i};
605            $i++;
606         }
607         $lit_cnt +=2; /* add the { and } characters */
608         $s = '';
609         for ($j = 0; $j < $lit_cnt; $j++) {
610            $i++;
611            $s .= $read{$i};
612         }
613         return $s;
614     }
615     
616     function parseQuote($read, $i) {
617         $i++;
618         $s = '';
619         while ($read{$i} != '"') {
620            if ($read{$i} == '\\') {
621                $i++;
622            } 
623            $s .= $read{$i};
624            $i++;
625         }
626         return $s;
627     }
628     
629     function parseAddress($read, $i) {
630         $arg_a = array();
631         while ($read{$i} != ')' ) { //&& $i < count($read)) {
632            $char = strtoupper($read{$i});
633            switch ($char) {
634              case '"':
635                $arg_a[] = $this->parseQuote($read,&$i);
636                break;
637              case '{': 
638                $arg_a[] = $this->parseLiteral($read,&$i);
639                break;
640              case 'N':   
641                if (strtolower(substr($read,$i,3)) == 'nil') {
642                   $arg_a[] = '';
643                   $i = $i+2;
644                }
645                break;
646              default:
647                break;
648            }
649            $i++;
650         }
651         if (count($arg_a) == 4) {
652             $adr = new address_structure();
653             $adr->personal = $arg_a[0];
654             $adr->adl = $arg_a[1];
655             $adr->mailbox = $arg_a[2];
656             $adr->host = $arg_a[3];
657         } else {
658            $adr = '';
659         }
660         return $adr;
661     }
662     
663     function parseDisposition($read,&$i) {
664         $arg_a = array();
665         while ($read{$i} != ')') {
666            switch ($read{$i}) {
667              case '"':
668                $arg_a[] = $this->parseQuote($read,&$i);
669                break;
670              case '{': 
671                $arg_a[] = $this->parseLiteral($read,&$i);
672                break;
673              case '(':
674                $arg_a[] = $this->parseProperties($read,&$i);
675                break;
676              default:
677                break;
678            }
679            $i++;
680         }
681         if (isset($arg_a[0])) {
682            $disp = new disposition($arg_a[0]);
683            if (isset($arg_a[1])) {
684               $disp->properties = $arg_a[1];
685            }
686         }
687         if (is_object($disp)) { 
688            return $disp;
689         }
690     }
691     
692     function parseLanguage($read,&$i) {
693         /* no idea how to process this one without examples */
694         $arg_a = array();
695         while ($read{$i} != ')') {
696            switch ($read{$i}) {
697              case '"':
698                $arg_a[] = $this->parseQuote($read,&$i);
699                break;
700              case '{': 
701                $arg_a[] = $this->parseLiteral($read,&$i);
702                break;
703              case '(':
704                $arg_a[] = $this->parseProperties($read,&$i);
705                break;
706              default:
707                break;
708            }
709            $i++;
710         }
711         if (isset($arg_a[0])) {
712            $lang = new language($arg_a[0]);
713            if (isset($arg_a[1])) {
714               $lang->properties = $arg_a[1];
715            }
716         }
717         if (is_object($lang)) { 
718            return $lang;
719         } else {
720            return '';
721         }
722     }
723     
724     function parseParenthesis($read,&$i) {
725         while ($read{$i} != ')') {
726            switch ($read{$i}) {
727              case '"':
728                $this->parseQuote($read,&$i);
729                break;
730              case '{': 
731                $this->parseLiteral($read,&$i);
732                break;
733              case '(':
734                $this->parseParenthesis($read,&$i);
735                break;
736              default:
737                break;
738            }
739            $i++;
740         } 
741     }
742
743     function findDisplayEntity ($entity = array(), $alt_order = array('text/plain','text/html')) {
744        $found = false;    
745        $type = $this->type0.'/'.$this->type1;
746        if ( $type == 'multipart/alternative') {
747             $msg = $this->findAlternativeEntity($alt_order);
748             if (count($msg->entities) == 0) {
749                 $entity[] = $msg->entity_id;
750             } else {
751                 $msg->findDisplayEntity(&$entity, $alt_order);
752             }
753             $found = true;          
754         } else  if ( $type == 'multipart/related') {
755             $msgs = $this->findRelatedEntity();
756             for ($i = 0; $i < count($msgs); $i++) {
757                 $msg = $msgs[$i];
758                 if (count($msg->entities) == 0) {
759                     $entity[] = $msg->entity_id;
760                 } else {
761                     $msg->findDisplayEntity(&$entity,$alt_order);
762                 }
763                 $found = true;          
764             }
765         } else if ( $this->type0 == 'text' &&
766              ( $this->type1 == 'plain' ||
767                $this->type1 == 'html' ||
768                $this->type1 == 'message') &&
769              isset($this->entity_id) ) {
770              if (count($this->entities) == 0) {
771                 if (!$this->header->disposition->name == 'attachment') {
772                    $entity[] = $this->entity_id;
773                 }
774              }
775         } 
776         $i = 0;
777         while ( isset($this->entities[$i]) &&  !$found &&
778                 !($this->entities[$i]->header->disposition->name 
779                 == 'attachment') &&
780                 !($this->entities[$i]->type0 == 'message' && 
781                   $this->entities[$i]->type1 == 'rfc822' )
782                 )
783                 {
784             $this->entities[$i]->findDisplayEntity(&$entity, $alt_order);
785             $i++;
786         }
787     
788         if ( !isset($entity[0]) ) {
789             $entity[]="";
790         }
791         return( $entity );
792     }
793
794     function findAlternativeEntity ($alt_order) {
795        /* if we are dealing with alternative parts then we choose the best 
796         * viewable message supported by SM.
797         */
798         $best_view = 0;
799         $ent_id = 0;
800         $k = 0; 
801         for ($i = 0; $i < count($this->entities); $i ++) {
802             $type = $this->entities[$i]->header->type0.'/'.$this->entities[$i]->header->type1;
803             if ($type == 'multipart/related') {
804                $type = $this->entities[$i]->header->type;
805             }
806             for ($j = $k; $j < count($alt_order); $j++) {
807                 if ($alt_order[$j] == $type && $j > $best_view) {
808                     $best_view = $j;
809                     $ent_id = $i;
810                     $k = $j;
811                 }
812             }
813         }
814         return $this->entities[$ent_id];
815     }
816     
817     function findRelatedEntity () {
818         $msgs = array(); 
819         for ($i = 0; $i < count($this->entities); $i ++) {
820             $type = $this->entities[$i]->header->type0.'/'.$this->entities[$i]->header->type1;
821             if ($this->header->type == $type) {
822                 $msgs[] = $this->entities[$i];
823             }
824         }
825         return $msgs;
826     }
827     
828     function getAttachments($exclude_id=array(), $result = array()) {
829        if ($this->type0 == 'message' && $this->type1 == 'rfc822') {
830           $this = $this->entities[0];
831        }
832        if (count($this->entities)) {
833           foreach ($this->entities as $entity) {
834             $exclude = false;
835             foreach ($exclude_id as $excl) {
836                if ($entity->entity_id == $excl) {
837                   $exclude = true;
838                }
839             }
840             if (!$exclude) {
841                if ($entity->type0 == 'multipart' && $entity->type1 == 'digest') {
842                   $result = $entity->getAttachments($exclude_id, $result);
843                } else if ($entity->type0 != 'multipart') {
844                   $result[] = $entity;
845                }
846             }
847           }
848        } else {
849             $exclude = false;
850             foreach ($exclude_id as $excl) {
851                if ($this->entity_id == $excl) {
852                   $exclude = true;
853                }
854             }
855             if (!$exclude) {
856                 $result[] = $this;
857             }
858        }
859        return $result;
860     }               
861     
862 }
863
864 class disposition {
865   function disposition($name) {
866      $this->name = $name;
867      $this->properties = array();
868   }
869 }
870
871 class language {
872   function language($name) {
873      $this->name = $name;
874      $this->properties = array();
875   }
876 }
877
878 ?>