Some fixes
[squirrelmail.git] / class / mime.class.php
CommitLineData
8f6b86cc 1<?php
2
3/**
1a09384c 4 * mime.class
8f6b86cc 5 *
6 * Copyright (c) 2002 The SquirrelMail Project Team
7 * Licensed under the GNU GPL. For full terms see the file COPYING.
8 *
27da67ae 9 *
8f6b86cc 10 * This contains functions needed to handle mime messages.
11 *
12 * $Id$
13 */
14
c9c7acf1 15
16
e8bedb2d 17/*
18 * rdc822_header class
19 * input: header_string or array
20 */
c9c7acf1 21class rfc822_header
22{
e8bedb2d 23 var $date = '',
24 $subject = '',
fc0dec58 25 $from = array(),
26 $sender = '',
27 $reply_to = array(),
28 $to = array(),
29 $cc = array(),
30 $bcc = array(),
31 $in_reply_to = '',
32 $message_id = '',
33 $mime = false,
34 $content_type = '',
35 $disposition = '',
36 $xmailer = '',
37 $priority = 3,
38 $dnt = '',
39 $mlist = array(),
40 $more_headers = array(); /* only needed for constructing headers
41 in smtp.php */
e8bedb2d 42
c52ffd66 43 function parseHeader($hdr)
44 {
45 if (is_array($hdr))
1d9392e4 46 {
47 $hdr = implode('',$hdr);
48 }
e8bedb2d 49 /* first we unfold the header */
1d9392e4 50 $hdr = trim(str_replace(array("\r\n\t","\r\n "),array('',''),$hdr));
51 /*
52 * now we can make a new header array with each element representing
53 * a headerline
54 */
55 $hdr = explode("\r\n" , $hdr);
56 foreach ($hdr as $line)
57 {
58 $pos = strpos($line,':');
59 if ($pos > 0)
60 {
61 $field = substr($line,0,$pos);
62 $value = trim(substr($line,$pos+1));
072dda67 63 if(!preg_match('/^X.*/i',$field)) {
1d9392e4 64 $value = $this->stripComments($value);
65 }
66 $this->parseField($field,$value);
67 }
68 }
69 if ($this->content_type == '')
70 {
71 $this->parseContentType('text/plain; charset=us-ascii');
72 }
e8bedb2d 73 }
319cf0d2 74
c52ffd66 75 function stripComments($value)
76 {
e8bedb2d 77 $cnt = strlen($value);
78 $s = '';
79 $i = 0;
c52ffd66 80 while ($i < $cnt)
81 {
e8bedb2d 82 switch ($value{$i})
83 {
84 case ('"'):
85 $s .= '"';
86 $i++;
c52ffd66 87 while ($value{$i} != '"')
88 {
89 if ($value{$i} == '\\')
90 {
e8bedb2d 91 $s .= '\\';
92 $i++;
93 }
94 $s .= $value{$i};
95 $i++;
c52ffd66 96 if ($i > $cnt) break;
e8bedb2d 97 }
98 $s .= $value{$i};
99 break;
100 case ('('):
c52ffd66 101 while ($value{$i} != ')')
102 {
103 if ($value{$i} == '\\')
104 {
e8bedb2d 105 $i++;
106 }
107 $i++;
108 }
109 break;
110 default:
111 $s .= $value{$i};
112 break;
113 }
114 $i++;
115 }
116 return $s;
117 }
319cf0d2 118
c9c7acf1 119 function parseField($field,$value)
120 {
e8bedb2d 121 $field = strtolower($field);
122 switch($field)
123 {
124 case ('date'):
125 $d = strtr($value, array(' ' => ' '));
126 $d = explode(' ', $d);
127 $this->date = getTimeStamp($d);
128 break;
129 case ('subject'):
130 $this->subject = $value;
131 break;
132 case ('from'):
133 $this->from = $this->parseAddress($value,true);
134 break;
135 case ('sender'):
136 $this->sender = $this->parseAddress($value);
137 break;
138 case ('reply-to'):
139 $this->reply_to = $this->parseAddress($value, true);
140 break;
141 case ('to'):
142 $this->to = $this->parseAddress($value, true);
143 break;
144 case ('cc'):
145 $this->cc = $this->parseAddress($value, true);
146 break;
147 case ('bcc'):
148 $this->bcc = $this->parseAddress($value, true);
149 break;
150 case ('in-reply-to'):
151 $this->in_reply_to = $value;
152 break;
153 case ('message_id'):
154 $this->message_id = $value;
155 break;
156 case ('disposition-notification-to'):
157 $this->dnt = $this->parseAddress($value);
158 break;
159 case ('mime-Version'):
160 $value = str_replace(' ','',$value);
c52ffd66 161 if ($value == '1.0')
162 {
e8bedb2d 163 $this->mime = true;
164 }
165 break;
166 case ('content-type'):
167 $this->parseContentType($value);
168 break;
169 case ('content-disposition'):
170 $this->parseDisposition($value);
171 break;
01d3a290 172 case ('user-agent'):
e8bedb2d 173 case ('x-mailer'):
174 $this->xmailer = $value;
175 break;
176 case ('x-priority'):
177 $this->priority = $value;
178 break;
179 case ('list-post'):
180 $this->mlist('post',$value);
181 break;
182 case ('list-reply'):
183 $this->mlist('reply',$value);
184 break;
185 case ('list-subscribe'):
186 $this->mlist('subscribe',$value);
187 break;
188 case ('list-unsubscribe'):
189 $this->mlist('unsubscribe',$value);
190 break;
191 case ('list-archive'):
192 $this->mlist('archive',$value);
193 break;
194 case ('list-owner'):
195 $this->mlist('owner',$value);
196 break;
197 case ('list-help'):
198 $this->mlist('help',$value);
199 break;
200 case ('list-id'):
201 $this->mlist('id',$value);
202 break;
203 default:
204 break;
205 }
206 }
207
c9c7acf1 208 function parseAddress($address, $ar=false, $addr_ar = array(), $group = '')
209 {
e8bedb2d 210 $pos = 0;
211 $j = strlen( $address );
212 $name = '';
213 $addr = '';
214 while ( $pos < $j ) {
215 switch ($address{$pos})
216 {
217 case ('"'): /* get the personal name */
218 $pos++;
c52ffd66 219 if ($address{$pos} == '"')
220 {
e8bedb2d 221 $pos++;
c52ffd66 222 } else
223 {
224 while ( $pos < $j && $address{$pos} != '"')
225 {
226 if (substr($address, $pos, 2) == '\\"')
227 {
228 $name .= $address{$pos};
229 $pos++;
230 } elseif (substr($address, $pos, 2) == '\\\\')
231 {
232 $name .= $address{$pos};
233 $pos++;
234 }
235 $name .= $address{$pos};
e8bedb2d 236 $pos++;
c52ffd66 237 }
e8bedb2d 238 }
239 $pos++;
240 break;
241 case ('<'): /* get email address */
242 $addr_start=$pos;
243 $pos++;
c52ffd66 244 while ( $pos < $j && $address{$pos} != '>' )
245 {
e8bedb2d 246 $addr .= $address{$pos};
247 $pos++;
248 }
249 $pos++;
250 break;
251 case ('('): /* rip off comments */
252 $addr_start=$pos;
253 $pos++;
c52ffd66 254 while ( $pos < $j && $address{$pos} != ')' )
255 {
e8bedb2d 256 $addr .= $address{$pos};
257 $pos++;
258 }
259 $address_start = substr($address,0,$addr_start);
260 $address_end = substr($address,$pos+1);
261 $address = $address_start . $address_end;
262 $j = strlen( $address );
263 $pos = $addr_start;
264 $pos++;
265 break;
266 case (','): /* we reached a delimiter */
c52ffd66 267 if ($addr == '')
268 {
e8bedb2d 269 $addr = substr($address,0,$pos);
270 } elseif ($name == '') {
8c3c4634 271 $name = trim(substr($address,0,$addr_start));
e8bedb2d 272 }
273
274 $at = strpos($addr, '@');
275 $addr_structure = new address_structure();
276 $addr_structure->personal = $name;
277 $addr_structure->group = $group;
c52ffd66 278 if ($at)
279 {
e8bedb2d 280 $addr_structure->mailbox = substr($addr,0,$at);
281 $addr_structure->host = substr($addr,$at+1);
c52ffd66 282 } else
283 {
e8bedb2d 284 $addr_structure->mailbox = $addr;
285 }
286 $address = trim(substr($address,$pos+1));
287 $j = strlen( $address );
288 $pos = 0;
289 $name = '';
290 $addr = '';
291 $addr_ar[] = $addr_structure;
292 break;
293 case (':'): /* process the group addresses */
294 /* group marker */
295 $group = substr($address,0,$pos);
296 $address = substr($address,$pos+1);
297 $result = $this->parseAddress($address, $ar, $addr_ar, $group);
298 $addr_ar = $result[0];
299 $pos = $result[1];
300 $address = substr($address,$pos);
301 $j = strlen( $address );
302 $group = '';
303 $pos++;
304 break;
305 case (';'):
c52ffd66 306 if ($group)
307 {
e8bedb2d 308 $address = substr($address, 0, $pos-1);
309 }
310 $pos++;
311 break;
312 default:
313 $pos++;
314 break;
315 }
316
317 }
c52ffd66 318 if ($addr == '')
319 {
e8bedb2d 320 $addr = substr($address,0,$pos);
c52ffd66 321 } elseif ($name == '')
322 {
8c3c4634 323 $name = trim(substr($address,0,$addr_start));
e8bedb2d 324 }
325 $at = strpos($addr, '@');
326 $addr_structure = new address_structure();
327 $addr_structure->group = $group;
c52ffd66 328 if ($at)
329 {
e8bedb2d 330 $addr_structure->mailbox = trim(substr($addr,0,$at));
331 $addr_structure->host = trim(substr($addr,$at+1));
c52ffd66 332 } else
333 {
e8bedb2d 334 $addr_structure->mailbox = trim($addr);
335 }
c52ffd66 336 if ($group && $addr == '') /* no addresses found in group */
337 {
e8bedb2d 338 $name = "$group: Undisclosed recipients;";
339 $addr_structure->personal = $name;
340 $addr_ar[] = $addr_structure;
341 return (array($addr_ar,$pos+1));
c52ffd66 342 } else
343 {
e8bedb2d 344 $addr_structure->personal = $name;
c52ffd66 345 if ($name || $addr)
346 {
e8bedb2d 347 $addr_ar[] = $addr_structure;
348 }
349 }
c52ffd66 350 if ($ar)
351 {
e8bedb2d 352 return ($addr_ar);
c52ffd66 353 } else
354 {
e8bedb2d 355 return ($addr_ar[0]);
356 }
8f6b86cc 357 }
e8bedb2d 358
c52ffd66 359 function parseContentType($value)
360 {
e8bedb2d 361 $pos = strpos($value,';');
362 $props = '';
c52ffd66 363 if ($pos > 0)
364 {
e8bedb2d 365 $type = trim(substr($value,0,$pos));
366 $props = trim(substr($type,$pos+1));
c52ffd66 367 } else
368 {
e8bedb2d 369 $type = $value;
370 }
371 $content_type = new content_type($type);
c52ffd66 372 if ($props)
373 {
e8bedb2d 374 $properties = $this->parseProperties($props);
c52ffd66 375 if (!isset($properties['charset']))
376 {
e8bedb2d 377 $properties['charset'] = 'us-ascii';
378 }
379 $content_type->properties = $this->parseProperties($props);
380 }
381 $this->content_type = $content_type;
382 }
383
c52ffd66 384 function parseProperties($value)
385 {
e8bedb2d 386 $propArray = explode(';',$value);
387 $propResultArray = array();
c52ffd66 388 foreach ($propArray as $prop)
389 {
e8bedb2d 390 $prop = trim($prop);
391 $pos = strpos($prop,'=');
c52ffd66 392 if ($pos>0)
393 {
e8bedb2d 394 $key = trim(substr($prop,0,$pos));
395 $val = trim(substr($prop,$pos+1));
c52ffd66 396 if ($val{0} == '"')
397 {
e8bedb2d 398 $val = substr($val,1,-1);
399 }
400 $propResultArray[$key] = $val;
401 }
402 }
403 return $propResultArray;
404 }
405
c52ffd66 406 function parseDisposition($value)
407 {
e8bedb2d 408 $pos = strpos($value,';');
409 $props = '';
c52ffd66 410 if ($pos > 0)
411 {
e8bedb2d 412 $name = trim(substr($value,0,$pos));
413 $props = trim(substr($type,$pos+1));
c52ffd66 414 } else
415 {
e8bedb2d 416 $name = $value;
417 }
418 $props_a = $this->parseProperties($props);
419 $disp = new disposition($name);
420 $disp->properties = $props_a;
421 $this->disposition = $disp;
422 }
423
c52ffd66 424 function mlist($field, $value)
425 {
e8bedb2d 426 $res_a = array();
427 $value_a = explode(',',$value);
428 foreach ($value_a as $val) {
429 $val = trim($val);
c52ffd66 430 if ($val{0} == '<')
431 {
e8bedb2d 432 $val = substr($val,1,-1);
433 }
c52ffd66 434 if (substr($val,0,7) == 'mailto:')
435 {
e8bedb2d 436 $res_a['mailto'] = substr($val,7);
c52ffd66 437 } else
438 {
e8bedb2d 439 $res_a['href'] = $val;
440 }
441 }
442 $this->mlist[$field] = $res_a;
443 }
444
319cf0d2 445 /*
446 * function to get the addres strings out of the header.
447 * Arguments: string or array of strings !
448 * example1: header->getAddr_s('to').
449 * example2: header->getAddr_s(array('to','cc','bcc'))
450 */
c52ffd66 451 function getAddr_s($arr, $separator=', ')
452 {
453 if (is_array($arr))
454 {
319cf0d2 455 $s = '';
c52ffd66 456 foreach($arr as $arg )
457 {
319cf0d2 458 $result = $this->getAddr_s($arg);
c52ffd66 459 if ($result)
460 {
e8bedb2d 461 $s .= $separator . $result;
319cf0d2 462 }
463 }
464 if ($s) $s = substr($s,2);
465 return $s;
c52ffd66 466 } else
467 {
319cf0d2 468 $s = '';
469 eval('$addr = $this->'.$arr.';') ;
c52ffd66 470 if (is_array($addr))
471 {
472 foreach ($addr as $addr_o)
473 {
474 if (is_object($addr_o))
475 {
e8bedb2d 476 $s .= $addr_o->getAddress() . $separator;
319cf0d2 477 }
478 }
e8bedb2d 479 $s = substr($s,0,-strlen($separator));
c52ffd66 480 } else
481 {
482 if (is_object($addr))
483 {
319cf0d2 484 $s .= $addr->getAddress();
485 }
486 }
487 return $s;
488 }
8f6b86cc 489 }
319cf0d2 490
c52ffd66 491 function getAddr_a($arg, $excl_arr=array(), $arr = array())
492 {
493 if (is_array($arg))
494 {
495 foreach($arg as $argument )
496 {
319cf0d2 497 $arr = $this->getAddr_a($argument, $excl_arr, $arr);
498 }
499 return $arr;
c52ffd66 500 } else
501 {
319cf0d2 502 eval('$addr = $this->'.$arg.';') ;
c52ffd66 503 if (is_array($addr))
504 {
505 foreach ($addr as $addr_o)
506 {
507 if (is_object($addr_o))
508 {
509 if (isset($addr_o->host) && $addr_o->host !='')
510 {
319cf0d2 511 $email = $addr_o->mailbox.'@'.$addr_o->host;
c52ffd66 512 } else
513 {
319cf0d2 514 $email = $addr_o->mailbox;
515 }
516 $email = strtolower($email);
c52ffd66 517 if ($email && !isset($arr[$email]) && !isset($excl_arr[$email]))
518 {
319cf0d2 519 $arr[$email] = $addr_o->personal;
520 }
521 }
522 }
c52ffd66 523 } else
524 {
525 if (is_object($addr))
526 {
527 if (isset($addr->host))
528 {
319cf0d2 529 $email = $addr->mailbox.'@'.$addr->host;
c52ffd66 530 } else
531 {
319cf0d2 532 $email = $addr->mailbox;
533 }
534 $email = strtolower($email);
c52ffd66 535 if ($email && !isset($arr[$email]) && !isset($excl_arr[$email]))
536 {
319cf0d2 537 $arr[$email] = $addr->personal;
538 }
539 }
540 }
541 return $arr;
542 }
8f6b86cc 543 }
e8bedb2d 544
c52ffd66 545 function getContentType($type0, $type1)
546 {
e8bedb2d 547 $type0 = $this->content_type->type0;
548 $type1 = $this->content_type->type1;
549 return $this->content_type->properties;
550 }
8f6b86cc 551}
552
c52ffd66 553class msg_header
554{
e8bedb2d 555 /** msg_header contains all variables available in a bodystructure **/
556 /** entity like described in rfc2060 **/
557
558 var $type0 = '',
559 $type1 = '',
560 $parameters = array(),
561 $id = 0,
562 $description = '',
563 $encoding='',
564 $size = 0,
565 $md5='',
566 $disposition = '',
567 $language='';
568
569 /*
570 * returns addres_list of supplied argument
571 * arguments: array('to', 'from', ...) or just a string like 'to'.
572 * result: string: address1, addres2, ....
573 */
574
c52ffd66 575 function setVar($var, $value)
576 {
e8bedb2d 577 $this->{$var} = $value;
578 }
579
c52ffd66 580 function getParameter($par)
581 {
e8bedb2d 582 $value = strtolower($par);
c52ffd66 583 if (isset($this->parameters[$par]))
584 {
e8bedb2d 585 return $this->parameters[$par];
586 }
587 return '';
588 }
589
c52ffd66 590 function setParameter($parameter, $value)
591 {
e8bedb2d 592 $this->parameters[strtolower($parameter)] = $value;
593 }
594}
595
596
597
c52ffd66 598class address_structure
599{
319cf0d2 600 var $personal = '', $adl = '', $mailbox = '', $host = '', $group = '';
8f6b86cc 601
c52ffd66 602 function getAddress($full=true)
603 {
604 if (is_object($this))
605 {
606 if (isset($this->host) && $this->host !='')
607 {
e8bedb2d 608 $email = $this->mailbox.'@'.$this->host;
c52ffd66 609 } else
610 {
319cf0d2 611 $email = $this->mailbox;
e02d0fa7 612 }
c52ffd66 613 if (trim($this->personal) !='')
614 {
615 if ($email)
616 {
e8bedb2d 617 $addr = '"' . $this->personal . '" <' .$email.'>';
c52ffd66 618 } else
619 {
319cf0d2 620 $addr = $this->personal;
621 }
622 $best_dpl = $this->personal;
c52ffd66 623 } else
624 {
319cf0d2 625 $addr = $email;
626 $best_dpl = $email;
627 }
c52ffd66 628 if ($full)
629 {
319cf0d2 630 return $addr;
c52ffd66 631 } else
632 {
319cf0d2 633 return $best_dpl;
634 }
635 } else return '';
636 }
8f6b86cc 637}
638
c52ffd66 639class message
640{
8f6b86cc 641 /** message is the object that contains messages. It is a recursive
642 object in that through the $entities variable, it can contain
643 more objects of type message. See documentation in mime.txt for
644 a better description of how this works.
645 **/
e8bedb2d 646 var $rfc822_header = '',
647 $mime_header = '',
648 $flags = '',
649 $type0='',
650 $type1='',
651 $entities = array(),
652 $parent_ent, $entity,
319cf0d2 653 $parent = '', $decoded_body='',
654 $is_seen = 0, $is_answered = 0, $is_deleted = 0, $is_flagged = 0,
e8bedb2d 655 $is_mdnsent = 0,
c52ffd66 656 $body_part = '',
657 $offset = 0, /* for fetching body parts out of raw messages */
658 $length = 0; /* for fetching body parts out of raw messages */
8f6b86cc 659
c52ffd66 660 function setEnt($ent)
661 {
8f6b86cc 662 $this->entity_id= $ent;
663 }
319cf0d2 664
c52ffd66 665 function addEntity ($msg)
666 {
8f6b86cc 667 $msg->parent = &$this;
668 $this->entities[] = $msg;
669 }
670
812843b7 671 function getFilename()
672 {
673 $filename = '';
674 if (is_object($this->header->disposition))
675 {
676 $filename = $this->header->disposition->getproperty('filename');
677 if (!$filename)
678 {
679 $filename = $this->header->disposition->getproperty('name');
680 }
681 }
682 if (!$filename)
683 {
684 $filename = 'untitled-'.$this->entity_id;
685 }
686 return $filename;
687 }
688
689
c52ffd66 690 function addRFC822Header($read)
691 {
692 $header = new rfc822_header();
693 $this->rfc822_header = $header->parseHeader($read);
8f6b86cc 694 }
695
c52ffd66 696 function getEntity($ent)
697 {
8f6b86cc 698 $cur_ent = $this->entity_id;
319cf0d2 699 $msg = $this;
c52ffd66 700 if ($cur_ent == '' || $cur_ent == '0')
701 {
319cf0d2 702 $cur_ent_a = array();
c52ffd66 703 } else
704 {
319cf0d2 705 $cur_ent_a = explode('.',$this->entity_id);
706 }
707 $ent_a = explode('.',$ent);
708
709 $cnt = count($ent_a);
8f6b86cc 710
c52ffd66 711 for ($i=0;$i<$cnt -1;$i++)
712 {
713 if (isset($cur_ent_a[$i]) && $cur_ent_a[$i] != $ent_a[$i])
714 {
319cf0d2 715 $msg = $msg->parent;
716 $cur_ent_a = explode('.',$msg->entity_id);
717 $i--;
c52ffd66 718 } else if (!isset($cur_ent_a[$i]))
719 {
720 if (isset($msg->entities[($ent_a[$i]-1)]))
721 {
319cf0d2 722 $msg = $msg->entities[($ent_a[$i]-1)];
723 } else {
724 $msg = $msg->entities[0];
725 }
726 }
c52ffd66 727 if ($msg->type0 == 'message' && $msg->type1 == 'rfc822')
728 {
319cf0d2 729 /*this is a header for a message/rfc822 entity */
730 $msg = $msg->entities[0];
731 }
732 }
08c18186 733
c52ffd66 734 if ($msg->type0 == 'message' && $msg->type1 == 'rfc822')
735 {
319cf0d2 736 /*this is a header for a message/rfc822 entity */
737 $msg = $msg->entities[0];
738 }
8f6b86cc 739
a2aea42e 740 if (isset($msg->entities[($ent_a[$cnt-1])-1]))
c52ffd66 741 {
a2aea42e 742 if (is_object($msg->entities[($ent_a[$cnt-1])-1]))
743 {
744 $msg = $msg->entities[($ent_a[$cnt-1]-1)];
745 }
746 }
08c18186 747
319cf0d2 748 return $msg;
8f6b86cc 749 }
e8bedb2d 750
c52ffd66 751 function setBody($s)
752 {
e8bedb2d 753 $this->body_part = $s;
754 }
755
c52ffd66 756 function clean_up()
757 {
e8bedb2d 758 $msg = $this;
759 $msg->body_part = '';
760 $i=0;
c52ffd66 761 while ( isset($msg->entities[$i]))
762 {
e8bedb2d 763 $msg->entities[$i]->clean_up();
764 $i++;
765 }
766 }
319cf0d2 767
c52ffd66 768 function getMailbox()
769 {
770 $msg = $this;
771 while (is_object($msg->parent))
772 {
319cf0d2 773 $msg = $msg->parent;
c52ffd66 774 }
775 return $msg->mailbox;
319cf0d2 776 }
777
c52ffd66 778 function calcEntity($msg)
779 {
780 if ($this->type0 == 'message' && $this->type1 == 'rfc822')
781 {
782 $msg->entity_id = $this->entity_id .'.0'; /* header of message/rfc822 */
783 } else if (isset($this->entity_id) && $this->entity_id !='')
784 {
785 $ent_no = count($this->entities)+1;
786 $par_ent = substr($this->entity_id,-2);
787 if ($par_ent{0} == '.')
788 {
789 $par_ent = $par_ent{1};
790 }
791 if ($par_ent == '0')
792 {
793 $ent_no = count($this->entities)+1;
794 if ($ent_no > 0)
795 {
796 $ent = substr($this->entity_id,0,strrpos($this->entity_id,'.'));
797 if ($ent)
798 {
799 $ent = $ent . ".$ent_no";
800 } else
801 {
802 $ent = $ent_no;
803 }
804 $msg->entity_id = $ent;
805 } else
806 {
807 $msg->entity_id = $ent_no;
808 }
809 } else
810 {
811 $ent = $this->entity_id . ".$ent_no";
812 $msg->entity_id = $ent;
813 }
814 } else
815 {
816 $msg->entity_id = '0';
817 }
818 return $msg->entity_id;
819 }
820
821
8f6b86cc 822 /*
823 * Bodystructure parser, a recursive function for generating the
824 * entity-tree with all the mime-parts.
825 *
826 * It follows RFC2060 and stores all the described fields in the
827 * message object.
828 *
829 * Question/Bugs:
830 *
831 * Ask for me (Marc Groot Koerkamp, stekkel@users.sourceforge.net.
832 *
833 */
c52ffd66 834 function parseStructure($read, $i=0)
835 {
319cf0d2 836 $arg_no = 0;
837 $arg_a = array();
838 $cnt = strlen($read);
c52ffd66 839 while ($i < $cnt)
840 {
319cf0d2 841 $char = strtoupper($read{$i});
c52ffd66 842 switch ($char)
843 {
319cf0d2 844 case '(':
c52ffd66 845 if ($arg_no == 0 )
846 {
847 if (!isset($msg))
848 {
319cf0d2 849 $msg = new message();
850 $hdr = new msg_header();
851 $hdr->type0 = 'text';
852 $hdr->type1 = 'plain';
853 $hdr->encoding = 'us-ascii';
c52ffd66 854 $msg->entity_id = $this->calcEntity($msg);
855 } else
856 {
319cf0d2 857 $msg->header->type0 = 'multipart';
858 $msg->type0 = 'multipart';
c52ffd66 859 while ($read{$i} == '(')
860 {
861 $res = $msg->parseStructure($read,$i);
862 $i = $res[1];
863 $msg->addEntity($res[0]);
319cf0d2 864 }
865 }
c52ffd66 866 } else
867 {
e8bedb2d 868 switch ($arg_no)
869 {
870 case 1:
319cf0d2 871 /* multipart properties */
872 $i++;
c52ffd66 873 $res = $this->parseProperties($read,$i);
924b0cac 874
c52ffd66 875 $arg_a[] = $res[0];
876 $i = $res[1];
319cf0d2 877 $arg_no++;
878 break;
e8bedb2d 879 case 2:
c52ffd66 880 if (isset($msg->type0) && $msg->type0 == 'multipart')
881 {
319cf0d2 882 $i++;
c52ffd66 883 $res = $msg->parseDisposition($read,$i);
884 $arg_a[] = $res[0];
885 $i = $res[1];
886 } else /* properties */
887 {
888 $res = $msg->parseProperties($read,$i);
889 $arg_a[] = $res[0];
890 $i = $res[1];
319cf0d2 891 }
892 $arg_no++;
893 break;
e8bedb2d 894 case 3:
c52ffd66 895 if (isset($msg->type0) && $msg->type0 == 'multipart')
896 {
08c18186 897 $i++;
c52ffd66 898 $res= $msg->parseLanguage($read,$i);
899 $arg_a[] = $res[0];
900 $i = $res[1];
08c18186 901 }
e8bedb2d 902 case 7:
c52ffd66 903 if ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822')
904 {
319cf0d2 905 $msg->header->type0 = $arg_a[0];
906 $msg->type0 = $arg_a[0];
319cf0d2 907 $msg->header->type1 = $arg_a[1];
908 $msg->type1 = $arg_a[1];
e8bedb2d 909 $rfc822_hdr = new rfc822_header();
c52ffd66 910 $res = $msg->parseEnvelope($read,$i,$rfc822_hdr);
911 $i = $res[1];
912 $msg->rfc822_header = $res[0];
319cf0d2 913 $i++;
c52ffd66 914 while ($i < $cnt && $read{$i} != '(')
915 {
319cf0d2 916 $i++;
917 }
c52ffd66 918 $res = $msg->parseStructure($read,$i);
919 $i = $res[1];
920 $msg->addEntity($res[0]);
319cf0d2 921 }
922 break;
e8bedb2d 923 case 8:
319cf0d2 924 $i++;
c52ffd66 925 $res = $msg->parseDisposition($read,$i);
926 $arg_a[] = $res[0];
927 $i = $res[1];
319cf0d2 928 $arg_no++;
929 break;
e8bedb2d 930 case 9:
319cf0d2 931 if ($arg_a[0] == 'text' ||
c52ffd66 932 ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822'))
933 {
319cf0d2 934 $i++;
c52ffd66 935 $res = $msg->parseDisposition($read,$i);
936 $arg_a[] = $res[0];
937 $i = $res[1];
938 } else
939 {
31e0cfba 940 $i++;
c52ffd66 941 $res = $msg->parseLanguage($read,$i);
942 $arg_a[] = $res[0];
943 $i = $res[1];
319cf0d2 944 }
945 $arg_no++;
946 break;
e8bedb2d 947 case 10:
319cf0d2 948 if ($arg_a[0] == 'text' ||
c52ffd66 949 ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822'))
950 {
31e0cfba 951 $i++;
c52ffd66 952 $res = $msg->parseLanguage($read,$i);
953 $arg_a[] = $res[0];
954 $i = $res[1];
955 } else
956 {
957 $i = $msg->parseParenthesis($read,$i);
319cf0d2 958 $arg_a[] = ''; /* not yet desribed in rfc2060 */
959 }
960 $arg_no++;
961 break;
e8bedb2d 962 default:
319cf0d2 963 /* unknown argument, skip this part */
c52ffd66 964 $i = $msg->parseParenthesis($read,$i);
319cf0d2 965 $arg_a[] = '';
966 $arg_no++;
967 break;
968 } /* switch */
969 }
970 break;
971 case '"':
972 /* inside an entity -> start processing */
973 $debug = substr($read,$i,20);
c52ffd66 974 $res = $msg->parseQuote($read,$i);
975 $arg_s = $res[0];
976 $i = $res[1];
319cf0d2 977 $arg_no++;
978 if ($arg_no < 3) $arg_s = strtolower($arg_s); /* type0 and type1 */
979 $arg_a[] = $arg_s;
980 break;
e8bedb2d 981 case 'n':
319cf0d2 982 case 'N':
983 /* probably NIL argument */
08c18186 984 if (strtoupper(substr($read,$i,4)) == 'NIL ' ||
c52ffd66 985 strtoupper(substr($read,$i,4)) == 'NIL)')
986 {
319cf0d2 987 $arg_a[] = '';
988 $arg_no++;
989 $i = $i+2;
990 }
991 break;
992 case '{':
993 /* process the literal value */
c52ffd66 994 $res = $msg->parseLiteral($read,$i);
995 $arg_s = $res[0];
996 $i = $res[1];
319cf0d2 997 $arg_no++;
998 break;
999 case (is_numeric($read{$i}) ):
1000 /* process integers */
1001 if ($read{$i} == ' ') break;
1002 $arg_s = $read{$i};;
1003 $i++;
c52ffd66 1004 while (preg_match('/^[0-9]{1}$/',$read{$i}))
1005 {
319cf0d2 1006 $arg_s .= $read{$i};
1007 $i++;
1008 }
1009 $arg_no++;
1010 $arg_a[] = $arg_s;
1011 break;
1012 case ')':
c52ffd66 1013 if (isset($msg->type0) && $msg->type0 == 'multipart')
1014 {
319cf0d2 1015 $multipart = true;
c52ffd66 1016 } else
1017 {
319cf0d2 1018 $multipart = false;
1019 }
c52ffd66 1020 if (!$multipart)
1021 {
319cf0d2 1022 if ($arg_a[0] == 'text' ||
c52ffd66 1023 ($arg_a[0] == 'message' && $arg_a[1] == 'rfc822'))
1024 {
319cf0d2 1025 $shifted_args = true;
c52ffd66 1026 } else
1027 {
319cf0d2 1028 $shifted_args = false;
1029 }
1030 $hdr->type0 = $arg_a[0];
1031 $hdr->type1 = $arg_a[1];
8f6b86cc 1032
319cf0d2 1033 $msg->type0 = $arg_a[0];
1034 $msg->type1 = $arg_a[1];
8f6b86cc 1035
319cf0d2 1036 $arr = $arg_a[2];
c52ffd66 1037 if (is_array($arr))
1038 {
e8bedb2d 1039 $hdr->parameters = $arg_a[2];
319cf0d2 1040 }
1041 $hdr->id = str_replace( '<', '', str_replace( '>', '', $arg_a[3] ) );
1042 $hdr->description = $arg_a[4];
1043 $hdr->encoding = strtolower($arg_a[5]);
1044 $hdr->entity_id = $msg->entity_id;
1045 $hdr->size = $arg_a[6];
c52ffd66 1046 if ($shifted_args)
1047 {
319cf0d2 1048 $hdr->lines = $arg_a[7];
c52ffd66 1049 if (isset($arg_a[8]))
1050 {
319cf0d2 1051 $hdr->md5 = $arg_a[8];
1052 }
c52ffd66 1053 if (isset($arg_a[9]))
1054 {
319cf0d2 1055 $hdr->disposition = $arg_a[9];
1056 }
c52ffd66 1057 if (isset($arg_a[10]))
1058 {
319cf0d2 1059 $hdr->language = $arg_a[10];
1060 }
c52ffd66 1061 } else
1062 {
1063 if (isset($arg_a[7]))
1064 {
319cf0d2 1065 $hdr->md5 = $arg_a[7];
1066 }
c52ffd66 1067 if (isset($arg_a[8]))
1068 {
319cf0d2 1069 $hdr->disposition = $arg_a[8];
1070 }
c52ffd66 1071 if (isset($arg_a[9]))
1072 {
319cf0d2 1073 $hdr->language = $arg_a[9];
1074 }
1075 }
1076 $msg->header = $hdr;
1077 $arg_no = 0;
1078 $i++;
c52ffd66 1079 if (substr($msg->entity_id,-2) == '.0' && $msg->type0 !='multipart')
1080 {
319cf0d2 1081 $msg->entity_id++;
1082 }
c52ffd66 1083 return (array($msg, $i));
1084 } else
1085 {
1086 $hdr->type0 = 'multipart';
1087 $hdr->type1 = $arg_a[0];
1088 $msg->type0 = 'multipart';
1089 $msg->type1 = $arg_a[0];
1090 if (is_array($arg_a[1]))
1091 {
1092 $hdr->parameters = $arg_a[1];
1093 }
1094 if (isset($arg_a[2]))
1095 {
1096 $hdr->disposition = $arg_a[2];
1097 }
1098 if (isset($arg_a[3]))
1099 {
1100 $hdr->language = $arg_a[3];
1101 }
1102 $msg->header = $hdr;
1103 return (array($msg, $i));
e8bedb2d 1104 }
319cf0d2 1105 default:
1106 break;
1107 } /* switch */
1108 $i++;
1109 } /* while */
1110 } /* parsestructure */
1111
c52ffd66 1112 function parseProperties($read, $i)
1113 {
319cf0d2 1114 $properties = array();
1115 $arg_s = '';
1116 $prop_name = '';
c52ffd66 1117 while ($read{$i} != ')')
1118 {
1119 if ($read{$i} == '"')
1120 {
1121 $res = $this->parseQuote($read,$i);
1122 $arg_s = $res[0];
1123 $i = $res[1];
1124 } else if ($read{$i} == '{')
1125 {
1126 $res = $this->parseLiteral($read,$i);
1127 $arg_s = $res[0];
1128 $i = $res[1];
319cf0d2 1129 }
c52ffd66 1130 if ($prop_name == '' && $arg_s)
1131 {
1132 $prop_name = strtolower($arg_s);
319cf0d2 1133 $properties[$prop_name] = '';
1134 $arg_s = '';
c52ffd66 1135 } elseif ($prop_name != '' && $arg_s != '')
1136 {
319cf0d2 1137 $properties[$prop_name] = $arg_s;
1138 $prop_name = '';
1139 $arg_s = '';
1140 }
1141 $i++;
1142 }
c52ffd66 1143 return (array($properties, $i));
8f6b86cc 1144 }
1145
c52ffd66 1146 function parseEnvelope($read, $i, $hdr)
1147 {
8f6b86cc 1148 $arg_no = 0;
319cf0d2 1149 $arg_a = array();
1150 $cnt = strlen($read);
c52ffd66 1151 while ($i< $cnt && $read{$i} != ')')
1152 {
319cf0d2 1153 $i++;
1154 $char = strtoupper($read{$i});
e8bedb2d 1155 switch ($char)
1156 {
1157 case '"':
c52ffd66 1158 $res = $this->parseQuote($read,$i);
1159 $arg_a[] = $res[0];
1160 $i = $res[1];
319cf0d2 1161 $arg_no++;
1162 break;
e8bedb2d 1163 case '{':
c52ffd66 1164 $res = $this->parseLiteral($read,$i);
1165 $arg_a[] = $res[0];
1166 $i = $res[1];
319cf0d2 1167 $arg_no++;
1168 break;
e8bedb2d 1169 case 'N':
319cf0d2 1170 /* probably NIL argument */
08c18186 1171 if (strtoupper(substr($read,$i,3)) == 'NIL') {
319cf0d2 1172 $arg_a[] = '';
1173 $arg_no++;
1174 $i = $i+2;
1175 }
1176 break;
e8bedb2d 1177 case '(':
319cf0d2 1178 /* Address structure
1179 * With group support.
1180 * Note: Group support is useless on SMTP connections
1181 * because the protocol doesn't support it
1182 */
1183 $addr_a = array();
1184 $group = '';
1185 $a=0;
c52ffd66 1186 while ($i < $cnt && $read{$i} != ')')
1187 {
1188 if ($read{$i} == '(')
1189 {
1190 $res = $this->parseAddress($read,$i);
1191 $addr = $res[0];
1192 $i = $res[1];
1193 if ($addr->host == '' && $addr->mailbox != '')
1194 {
319cf0d2 1195 /* start of group */
1196 $group = $addr->mailbox;
1197 $group_addr = $addr;
1198 $j = $a;
c52ffd66 1199 } elseif ($group && $addr->host == '' && $addr->mailbox == '')
1200 {
319cf0d2 1201 /* end group */
c52ffd66 1202 if ($a == $j+1) /* no group members */
1203 {
319cf0d2 1204 $group_addr->group = $group;
1205 $group_addr->mailbox = '';
1206 $group_addr->personal = "$group: Undisclosed recipients;";
1207 $addr_a[] = $group_addr;
1208 $group ='';
1209 }
c52ffd66 1210 } else
1211 {
319cf0d2 1212 $addr->group = $group;
1213 $addr_a[] = $addr;
1214 }
1215 $a++;
1216 }
1217 $i++;
1218 }
1219 $arg_a[] = $addr_a;
1220 break;
e8bedb2d 1221 default:
319cf0d2 1222 break;
1223 }
1224 $i++;
1225 }
c52ffd66 1226 if (count($arg_a) > 9)
1227 {
319cf0d2 1228 /* argument 1: date */
8f6b86cc 1229 $d = strtr($arg_a[0], array(' ' => ' '));
1230 $d = explode(' ', $d);
1231 $hdr->date = getTimeStamp($d);
319cf0d2 1232 /* argument 2: subject */
c52ffd66 1233 if (!trim($arg_a[1]))
1234 {
319cf0d2 1235 $arg_a[1]= _("(no subject)");
1236 }
1237 $hdr->subject = $arg_a[1];
1238 /* argument 3: from */
1239 $hdr->from = $arg_a[2][0];
1240 /* argument 4: sender */
1241 $hdr->sender = $arg_a[3][0];
1242 /* argument 5: reply-to */
1243 $hdr->replyto = $arg_a[4][0];
1244 /* argument 6: to */
1245 $hdr->to = $arg_a[5];
1246 /* argument 7: cc */
1247 $hdr->cc = $arg_a[6];
1248 /* argument 8: bcc */
1249 $hdr->bcc = $arg_a[7];
1250 /* argument 9: in-reply-to */
1251 $hdr->inreplyto = $arg_a[8];
1252 /* argument 10: message-id */
1253 $hdr->message_id = $arg_a[9];
08c18186 1254 }
c52ffd66 1255 return (array($hdr,$i));
8f6b86cc 1256 }
319cf0d2 1257
c52ffd66 1258 function parseLiteral($read, $i)
1259 {
319cf0d2 1260 $lit_cnt = '';
1261 $i++;
c52ffd66 1262 while ($read{$i} != '}')
1263 {
319cf0d2 1264 $lit_cnt .= $read{$i};
1265 $i++;
1266 }
1267 $lit_cnt +=2; /* add the { and } characters */
1268 $s = '';
c52ffd66 1269 for ($j = 0; $j < $lit_cnt; $j++)
1270 {
319cf0d2 1271 $i++;
1272 $s .= $read{$i};
1273 }
c52ffd66 1274 return (array($s, $i));
8f6b86cc 1275 }
319cf0d2 1276
c52ffd66 1277 function parseQuote($read, $i)
1278 {
319cf0d2 1279 $i++;
1280 $s = '';
c52ffd66 1281 while ($read{$i} != '"')
1282 {
1283 if ($read{$i} == '\\')
1284 {
319cf0d2 1285 $i++;
1286 }
1287 $s .= $read{$i};
1288 $i++;
1289 }
c52ffd66 1290 return (array($s, $i));
8f6b86cc 1291 }
319cf0d2 1292
c52ffd66 1293 function parseAddress($read, $i)
1294 {
319cf0d2 1295 $arg_a = array();
c52ffd66 1296 while ($read{$i} != ')' )
1297 {
319cf0d2 1298 $char = strtoupper($read{$i});
e8bedb2d 1299 switch ($char)
1300 {
1301 case '"':
c52ffd66 1302 $res = $this->parseQuote($read,$i);
1303 $arg_a[] = $res[0];
1304 $i = $res[1];
319cf0d2 1305 break;
e8bedb2d 1306 case '{':
c52ffd66 1307 $res = $this->parseLiteral($read,$i);
1308 $arg_a[] = $res[0];
1309 $i = $res[1];
319cf0d2 1310 break;
e8bedb2d 1311 case 'n':
1312 case 'N':
1313 if (strtoupper(substr($read,$i,3)) == 'NIL') {
319cf0d2 1314 $arg_a[] = '';
1315 $i = $i+2;
1316 }
08c18186 1317 break;
e8bedb2d 1318 default:
319cf0d2 1319 break;
1320 }
1321 $i++;
1322 }
c52ffd66 1323 if (count($arg_a) == 4)
1324 {
319cf0d2 1325 $adr = new address_structure();
1326 $adr->personal = $arg_a[0];
1327 $adr->adl = $arg_a[1];
1328 $adr->mailbox = $arg_a[2];
1329 $adr->host = $arg_a[3];
c52ffd66 1330 } else
1331 {
08c18186 1332 $adr = '';
1333 }
c52ffd66 1334 return (array($adr,$i));
8f6b86cc 1335 }
319cf0d2 1336
c52ffd66 1337 function parseDisposition($read,$i)
1338 {
8f6b86cc 1339 $arg_a = array();
c52ffd66 1340 while ($read{$i} != ')')
1341 {
e8bedb2d 1342 switch ($read{$i})
1343 {
1344 case '"':
c52ffd66 1345 $res = $this->parseQuote($read,$i);
1346 $arg_a[] = $res[0];
1347 $i = $res[1];
319cf0d2 1348 break;
e8bedb2d 1349 case '{':
c52ffd66 1350 $res = $this->parseLiteral($read,$i);
1351 $arg_a[] = $res[0];
1352 $i = $res[1];
319cf0d2 1353 break;
e8bedb2d 1354 case '(':
c52ffd66 1355 $res = $this->parseProperties($read,$i);
1356 $arg_a[] = $res[0];
1357 $i = $res[1];
319cf0d2 1358 break;
e8bedb2d 1359 default:
319cf0d2 1360 break;
1361 }
1362 $i++;
e02d0fa7 1363 }
c52ffd66 1364 if (isset($arg_a[0]))
1365 {
319cf0d2 1366 $disp = new disposition($arg_a[0]);
c52ffd66 1367 if (isset($arg_a[1]))
1368 {
319cf0d2 1369 $disp->properties = $arg_a[1];
1370 }
1371 }
c52ffd66 1372 if (is_object($disp))
1373 {
1374 return (array($disp, $i));
1375 } else
1376 {
1377 return (array('',$i));
08c18186 1378 }
8f6b86cc 1379 }
319cf0d2 1380
c52ffd66 1381 function parseLanguage($read,$i)
1382 {
08c18186 1383 /* no idea how to process this one without examples */
31e0cfba 1384 $arg_a = array();
c52ffd66 1385 while ($read{$i} != ')')
1386 {
e8bedb2d 1387 switch ($read{$i})
1388 {
1389 case '"':
c52ffd66 1390 $res = $this->parseQuote($read,$i);
1391 $arg_a[] = $res[0];
1392 $i = $res[1];
08c18186 1393 break;
e8bedb2d 1394 case '{':
c52ffd66 1395 $res = $this->parseLiteral($read,$i);
1396 $arg_a[] = $res[0];
1397 $i = $res[1];
08c18186 1398 break;
e8bedb2d 1399 case '(':
c52ffd66 1400 $res = $this->parseProperties($read,$i);
1401 $arg_a[] = $res[0];
1402 $i = $res[1];
08c18186 1403 break;
e8bedb2d 1404 default:
08c18186 1405 break;
1406 }
1407 $i++;
1408 }
c52ffd66 1409 if (isset($arg_a[0]))
1410 {
31e0cfba 1411 $lang = new language($arg_a[0]);
c52ffd66 1412 if (isset($arg_a[1]))
1413 {
31e0cfba 1414 $lang->properties = $arg_a[1];
1415 }
1416 }
c52ffd66 1417 if (is_object($lang))
1418 {
1419 return (array($lang, $i));
1420 } else
1421 {
1422 return (array('', $i));
31e0cfba 1423 }
8f6b86cc 1424 }
319cf0d2 1425
c52ffd66 1426 function parseParenthesis($read,$i)
1427 {
1428 while ($read{$i} != ')')
1429 {
e8bedb2d 1430 switch ($read{$i})
1431 {
1432 case '"':
c52ffd66 1433 $res = $this->parseQuote($read,$i);
1434 $i = $res[1];
319cf0d2 1435 break;
e8bedb2d 1436 case '{':
c52ffd66 1437 $res = $this->parseLiteral($read,$i);
1438 $i = $res[1];
319cf0d2 1439 break;
e8bedb2d 1440 case '(':
c52ffd66 1441 $res = $this->parseParenthesis($read,$i);
1442 $i = $res[1];
319cf0d2 1443 break;
e8bedb2d 1444 default:
319cf0d2 1445 break;
1446 }
1447 $i++;
1448 }
c52ffd66 1449 return $i;
1450 }
1451
1452 /* function to fill the message structure in case the bodystructure
1453 isn't available NOT FINISHED YET
1454 */
1455 function parseMessage($read, $type0, $type1)
1456 {
1457 switch ($type0)
1458 {
1459 case 'message':
1460 $rfc822_header = true;
1461 $mime_header = false;
1462 break;
1463 case 'multipart':
1464 $mime_header = true;
1465 $rfc822_header = false;
1466 break;
1467 default:
1468 return $read;
1469 }
1470
1471 for ($i=1; $i < $count; $i++)
1472 {
1473 $line = trim($body[$i]);
1474 if ( ( $mime_header || $rfc822_header) &&
1475 (preg_match("/^.*boundary=\"?(.+(?=\")|.+).*/i",$line,$reg)) )
1476 {
1477 $bnd = $reg[1];
1478 $bndreg = $bnd;
1479 $bndreg = str_replace("\\","\\\\",$bndreg);
1480 $bndreg = str_replace("?","\\?",$bndreg);
1481 $bndreg = str_replace("+","\\+",$bndreg);
1482 $bndreg = str_replace(".","\\.",$bndreg);
1483 $bndreg = str_replace("/","\\/",$bndreg);
1484 $bndreg = str_replace("-","\\-",$bndreg);
1485 $bndreg = str_replace("(","\\(",$bndreg);
1486 $bndreg = str_replace(")","\\)",$bndreg);
1487 } elseif ( $rfc822_header && $line == '' )
1488 {
1489 $rfc822_header = false;
1490 if ($msg->type0 == 'multipart')
1491 {
1492 $mime_header = true;
1493 }
1494 }
1495
1496 if (($line{0} == '-' || $rfc822_header) && isset($boundaries[0]))
1497 {
1498 $cnt=count($boundaries)-1;
1499 $bnd = $boundaries[$cnt]['bnd'];
1500 $bndreg = $boundaries[$cnt]['bndreg'];
1501
1502 $regstr = '/^--'."($bndreg)".".*".'/';
1503 if (preg_match($regstr,$line,$reg) )
1504 {
1505 $bndlen = strlen($reg[1]);
1506 $bndend = false;
1507 if (strlen($line) > ($bndlen + 3))
1508 {
1509 if ($line{$bndlen+2} == '-' && $line{$bndlen+3} == '-')
1510 $bndend = true;
1511 }
1512 if ($bndend)
1513 {
1514 /* calc offset and return $msg */
1515 // $entStr = CalcEntity("$entStr",-1);
1516 array_pop($boundaries);
1517 $mime_header = true;
1518 $bnd_end = true;
1519 } else
1520 {
1521 $mime_header = true;
1522 $bnd_end = false;
1523// $entStr = CalcEntity("$entStr",0);
1524 $content_indx++;
1525 }
1526 } else
1527 {
1528 if ($header)
1529 {
1530 }
1531 }
1532 }
1533 }
319cf0d2 1534 }
1535
c52ffd66 1536 function findDisplayEntity ($entity = array(), $alt_order = array('text/plain','text/html'))
1537 {
8f288482 1538 $found = false;
1539 $type = $this->type0.'/'.$this->type1;
1540 if ( $type == 'multipart/alternative')
1541 {
1542 $msg = $this->findAlternativeEntity($alt_order);
1543 if (count($msg->entities) == 0)
1544 {
1545 $entity[] = $msg->entity_id;
1546 } else
1547 {
1548 $entity = $msg->findDisplayEntity($entity, $alt_order);
1549 }
1550 $found = true;
1551 } else if ( $type == 'multipart/related')
1552 {
319cf0d2 1553 $msgs = $this->findRelatedEntity();
8f288482 1554 foreach ($msgs as $msg)
1555 {
1556 if (count($msg->entities) == 0)
1557 {
1558 $entity[] = $msg->entity_id;
1559 } else
1560 {
1561 $entity = $msg->findDisplayEntity($entity,$alt_order);
1562 }
1563 }
1564 if (count($msgs) > 0) {
1565 $found = true;
1566 }
1567 } else if ($this->type0 == 'text' &&
1568 ($this->type1 == 'plain' ||
1569 $this->type1 == 'html' ||
1570 $this->type1 == 'message') &&
1571 isset($this->entity_id) )
1572 {
1573 if (count($this->entities) == 0)
1574 {
1575 if (strtolower($this->header->disposition->name) != 'attachment')
1576 {
1577 $entity[] = $this->entity_id;
1578 }
1579 }
1580 }
1581 $i = 0;
1582 if(!$found) {
1583 foreach ($this->entities as $ent) {
1584 if(strtolower($ent->header->disposition->name) != 'attachment' &&
1585 ($ent->type0 != 'message' && $ent->type1 != 'rfc822'))
1586 {
1587 $entity = $ent->findDisplayEntity($entity, $alt_order);
1588 }
1589 }
1590 }
1591 /*
1592 while ( isset($this->entities[$i]) && !$found &&
1593 (strtolower($this->entities[$i]->header->disposition->name)
1594 != 'attachment') &&
1595 ($this->entities[$i]->type0 != 'message' &&
1596 $this->entities[$i]->type1 != 'rfc822' )
1597 )
1598 {
1599 $entity = $this->entities[$i]->findDisplayEntity($entity, $alt_order);
1600 $i++;
1601 }
1602 */
1603 return( $entity );
8f6b86cc 1604 }
319cf0d2 1605
c52ffd66 1606 function findAlternativeEntity ($alt_order)
1607 {
319cf0d2 1608 /* if we are dealing with alternative parts then we choose the best
1609 * viewable message supported by SM.
1610 */
1611 $best_view = 0;
8f288482 1612 $entity = array();
1613 $altcount = count($alt_order);
1614 foreach($this->entities as $ent)
1615 {
1616 $type = $ent->header->type0.'/'.$ent->header->type1;
1617 if ($type == 'multipart/related')
1618 {
1619 $type = $ent->header->getParameter('type');
1620 }
1621 for ($j = $best_view; $j < $altcount; $j++)
1622 {
1623 if ($alt_order[$j] == $type && $j >= $best_view)
1624 {
1625 $best_view = $j;
1626 $entity = $ent;
1627 }
1628 }
319cf0d2 1629 }
8f288482 1630 return $entity;
319cf0d2 1631 }
1632
c52ffd66 1633 function findRelatedEntity ()
1634 {
319cf0d2 1635 $msgs = array();
8f288482 1636 $entcount = count($this->entities);
1637 for ($i = 0; $i < $entcount; $i++)
1638 {
319cf0d2 1639 $type = $this->entities[$i]->header->type0.'/'.$this->entities[$i]->header->type1;
c52ffd66 1640 if ($this->header->getParameter('type') == $type)
8f288482 1641 {
1642 $msgs[] = $this->entities[$i];
1643 }
319cf0d2 1644 }
1645 return $msgs;
1646 }
1647
c52ffd66 1648 function getAttachments($exclude_id=array(), $result = array())
1649 {
1650 if ($this->type0 == 'message' && $this->type1 == 'rfc822')
1651 {
319cf0d2 1652 $this = $this->entities[0];
1653 }
c52ffd66 1654 if (count($this->entities))
1655 {
1656 foreach ($this->entities as $entity)
1657 {
319cf0d2 1658 $exclude = false;
c52ffd66 1659 foreach ($exclude_id as $excl)
1660 {
13c312be 1661 if ($entity->entity_id === $excl)
c52ffd66 1662 {
319cf0d2 1663 $exclude = true;
1664 }
1665 }
c52ffd66 1666 if (!$exclude)
1667 {
1a09384c 1668 if ($entity->type0 == 'multipart' &&
c52ffd66 1669 $entity->type1 != 'related')
1670 {
319cf0d2 1671 $result = $entity->getAttachments($exclude_id, $result);
c52ffd66 1672 } else if ($entity->type0 != 'multipart')
1673 {
319cf0d2 1674 $result[] = $entity;
1675 }
1676 }
1677 }
c52ffd66 1678 } else
1679 {
1680 $exclude = false;
1681 foreach ($exclude_id as $excl)
1682 {
1683 if ($this->entity_id == $excl)
1684 {
1685 $exclude = true;
1686 }
1687 }
1688 if (!$exclude)
1689 {
1690 $result[] = $this;
1691 }
319cf0d2 1692 }
1693 return $result;
1694 }
8f6b86cc 1695}
1696
c52ffd66 1697class smime_message
1698{
1699}
1700
1701class disposition
1702{
1703 function disposition($name)
1704 {
e8bedb2d 1705 $this->name = $name;
1706 $this->properties = array();
1707 }
924b0cac 1708
1709 function getProperty($par)
1710 {
1711 $value = strtolower($par);
1712 if (isset($this->properties[$par]))
1713 {
1714 return $this->properties[$par];
1715 }
1716 return '';
1717 }
1718
8f6b86cc 1719}
1720
c52ffd66 1721class language
1722{
1723 function language($name)
1724 {
e8bedb2d 1725 $this->name = $name;
1726 $this->properties = array();
1727 }
1728}
1729
c52ffd66 1730class content_type
1731{
e8bedb2d 1732 var $type0='text',
1733 $type1='plain',
1734 $properties='';
c52ffd66 1735 function content_type($type)
1736 {
e8bedb2d 1737 $pos = strpos($type,'/');
c52ffd66 1738 if ($pos > 0)
1739 {
e8bedb2d 1740 $this->type0 = substr($type,0,$pos);
1741 $this->type1 = substr($type,$pos+1);
c52ffd66 1742 } else
1743 {
e8bedb2d 1744 $this->type0 = $type;
1745 }
1746 $this->properties = array();
c52ffd66 1747 }
31e0cfba 1748}
1749
fc0dec58 1750?>