Source for file Message.class.php

Documentation is available at Message.class.php

  1. <?php
  2.  
  3. /**
  4.  * Message.class.php
  5.  *
  6.  * This file contains functions needed to handle mime messages.
  7.  *
  8.  * @copyright &copy; 2003-2006 The SquirrelMail Project Team
  9.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  10.  * @version $Id: Message.class.php,v 1.38 2006/07/15 12:00:44 tokul Exp $
  11.  * @package squirrelmail
  12.  * @subpackage mime
  13.  * @since 1.3.2
  14.  */
  15.  
  16. /**
  17.  * The object that contains a message.
  18.  *
  19.  * message is the object that contains messages. It is a recursive object in
  20.  * that through the $entities variable, it can contain more objects of type
  21.  * message. See documentation in mime.txt for a better description of how this
  22.  * works.
  23.  * @package squirrelmail
  24.  * @subpackage mime
  25.  * @since 1.3.0
  26.  */
  27. class Message {
  28.     /**
  29.      * rfc822header object
  30.      * @var object 
  31.      */
  32.     var $rfc822_header = '';
  33.     /**
  34.      * MessageHeader object
  35.      * @var object 
  36.      */
  37.     var $mime_header = '';
  38.     /**
  39.      * @var mixed 
  40.      */
  41.     var $flags = '';
  42.     /**
  43.      * Media type
  44.      * @var string 
  45.      */
  46.     var $type0='';
  47.     /**
  48.      * Media subtype
  49.      * @var string 
  50.      */
  51.     var $type1='';
  52.     /**
  53.      * Nested mime parts
  54.      * @var array 
  55.      */
  56.     var $entities = array();
  57.     /**
  58.      * Message part id
  59.      * @var string 
  60.      */
  61.     var $entity_id = '';
  62.     /**
  63.      * Parent message part id
  64.      * @var string 
  65.      */
  66.     var $parent_ent;
  67.     /**
  68.      * @var mixed 
  69.      */
  70.     var $entity;
  71.     /**
  72.      * @var mixed 
  73.      */
  74.     var $parent = '';
  75.     /**
  76.      * @var string 
  77.      */
  78.     var $decoded_body='';
  79.     /**
  80.      * Message \seen status
  81.      * @var boolean 
  82.      */
  83.     var $is_seen = 0;
  84.     /**
  85.      * Message \answered status
  86.      * @var boolean 
  87.      */
  88.     var $is_answered = 0;
  89.     /**
  90.      * Message \deleted status
  91.      * @var boolean 
  92.      */
  93.     var $is_deleted = 0;
  94.     /**
  95.      * Message \flagged status
  96.      * @var boolean 
  97.      */
  98.     var $is_flagged = 0;
  99.     /**
  100.      * Message mdn status
  101.      * @var boolean 
  102.      */
  103.     var $is_mdnsent = 0;
  104.     /**
  105.      * Message text body
  106.      * @var string 
  107.      */
  108.     var $body_part = '';
  109.     /**
  110.      * Message part offset
  111.      * for fetching body parts out of raw messages
  112.      * @var integer 
  113.      */
  114.     var $offset = 0;
  115.     /**
  116.      * Message part length
  117.      * for fetching body parts out of raw messages
  118.      * @var integer 
  119.      */
  120.     var $length = 0;
  121.     /**
  122.      * Local attachment filename location where the tempory attachment is
  123.      * stored. For use in delivery class.
  124.      * @var string 
  125.      */
  126.     var $att_local_name = '';
  127.  
  128.     /**
  129.      * @param string $ent entity id
  130.      */
  131.     function setEnt($ent{
  132.         $this->entity_id$ent;
  133.     }
  134.  
  135.     /**
  136.      * Add nested message part
  137.      * @param object $msg 
  138.      */
  139.     function addEntity ($msg{
  140.         $this->entities[$msg;
  141.     }
  142.  
  143.     /**
  144.      * Get file name used for mime part
  145.      * @return string file name
  146.      * @since 1.3.2
  147.      */
  148.     function getFilename({
  149.          $filename '';
  150.          $header $this->header;
  151.          if (is_object($header->disposition)) {
  152.               $filename $header->disposition->getProperty('filename');
  153.               if (trim($filename== ''{
  154.                   $name decodeHeader($header->disposition->getProperty('name'));
  155.                   if (!trim($name)) {
  156.                       $name $header->getParameter('name');
  157.                       if(!trim($name)) {
  158.                           if (!trim$header->id )) {
  159.                               $filename 'untitled-[' $this->entity_id . ']' ;
  160.                           else {
  161.                               $filename 'cid: ' $header->id;
  162.                           }
  163.                       else {
  164.                           $filename $name;
  165.                       }
  166.                   else {
  167.                       $filename $name;
  168.                   }
  169.               }
  170.          else {
  171.               $filename $header->getParameter('filename');
  172.               if (!trim($filename)) {
  173.                   $filename $header->getParameter('name');
  174.                   if (!trim($filename)) {
  175.                       if (!trim$header->id )) {
  176.                           $filename 'untitled-[' $this->entity_id . ']' ;
  177.                       else {
  178.                           $filename 'cid: ' $header->id;
  179.                       }
  180.                   }
  181.               }
  182.          }
  183.          return $filename;
  184.     }
  185.  
  186.     /**
  187.      * Add header object to message object.
  188.      * WARNING: Unfinished code. Don't expect it to work in older sm versions.
  189.      * @param mixed $read array or string with message headers
  190.      * @todo FIXME: rfc822header->parseHeader() does not return rfc822header object
  191.      */
  192.     function addRFC822Header($read{
  193.         $header new Rfc822Header();
  194.         $this->rfc822_header = $header->parseHeader($read);
  195.     }
  196.  
  197.     /**
  198.      * @param string $ent 
  199.      * @return mixed (object or string?)
  200.      */
  201.     function getEntity($ent{
  202.         $cur_ent $this->entity_id;
  203.         $msg $this;
  204.         if (($cur_ent == ''|| ($cur_ent == '0')) {
  205.             $cur_ent_a array();
  206.         else {
  207.             $cur_ent_a explode('.'$this->entity_id);
  208.         }
  209.         $ent_a explode('.'$ent);
  210.  
  211.         for ($i 0,$entCount count($ent_a1$i $entCount++$i{
  212.             if (isset($cur_ent_a[$i]&& ($cur_ent_a[$i!= $ent_a[$i])) {
  213.                 $msg $msg->parent;
  214.                 $cur_ent_a explode('.'$msg->entity_id);
  215.                 --$i;
  216.             else if (!isset($cur_ent_a[$i])) {
  217.                 if (isset($msg->entities[($ent_a[$i]-1)])) {
  218.                     $msg $msg->entities[($ent_a[$i]-1)];
  219.                 else {
  220.                     $msg $msg->entities[0];
  221.                 }
  222.             }
  223.             if (($msg->type0 == 'message'&& ($msg->type1 == 'rfc822')) {
  224.                 /*this is a header for a message/rfc822 entity */
  225.                 $msg $msg->entities[0];
  226.             }
  227.         }
  228.  
  229.         if (($msg->type0 == 'message'&& ($msg->type1 == 'rfc822')) {
  230.             /*this is a header for a message/rfc822 entity */
  231.             $msg $msg->entities[0];
  232.         }
  233.  
  234.         if (isset($msg->entities[($ent_a[$entCount])-1])) {
  235.             if (is_object($msg->entities[($ent_a[$entCount])-1])) {
  236.                 $msg $msg->entities[($ent_a[$entCount]-1)];
  237.             }
  238.         }
  239.  
  240.         return $msg;
  241.     }
  242.  
  243.     /**
  244.      * Set message body
  245.      * @param string $s message body
  246.      */
  247.     function setBody($s{
  248.         $this->body_part = $s;
  249.     }
  250.  
  251.     /**
  252.      * Clean message object
  253.      */
  254.     function clean_up({
  255.         $msg $this;
  256.         $msg->body_part '';
  257.  
  258.         foreach ($msg->entities as $m{
  259.             $m->clean_up();
  260.         }
  261.     }
  262.  
  263.     /**
  264.      * @return string 
  265.      */
  266.     function getMailbox({
  267.         $msg $this;
  268.         while (is_object($msg->parent)) {
  269.             $msg $msg->parent;
  270.         }
  271.         return $msg->mailbox;
  272.     }
  273.  
  274.     /*
  275.      * Bodystructure parser, a recursive function for generating the
  276.      * entity-tree with all the mime-parts.
  277.      *
  278.      * It follows RFC2060 and stores all the described fields in the
  279.      * message object.
  280.      *
  281.      * Question/Bugs:
  282.      *
  283.      * Ask for me (Marc Groot Koerkamp, [email protected])
  284.      * @param string $read
  285.      * @param integer $i
  286.      * @param mixed $sub_msg
  287.      * @return object Message object
  288.      * @todo define argument and return types
  289.      */
  290.     function parseStructure($read&$i$sub_msg ''{
  291.         $msg Message::parseBodyStructure($read$i$sub_msg);
  292.         if($msg$msg->setEntIds($msg,false,0);
  293.         return $msg;
  294.     }
  295.  
  296.     /**
  297.      * @param object $msg 
  298.      * @param mixed $init 
  299.      * @param integer $i 
  300.      * @todo document me
  301.      * @since 1.4.0
  302.      */
  303.     function setEntIds(&$msg,$init=false,$i=0{
  304.         $iCnt count($msg->entities);
  305.         if ($init !==false{
  306.             $iEntSub $i+1;
  307.             if ($msg->parent->type0 == 'message' &&
  308.                 $msg->parent->type1 == 'rfc822' &&
  309.                 $msg->type0 == 'multipart'{
  310.                 $iEntSub '0';
  311.             }
  312.             if ($init{
  313.                 $msg->entity_id "$init.$iEntSub";
  314.             else {
  315.                 $msg->entity_id $iEntSub;
  316.             }
  317.         else if ($iCnt{
  318.             $msg->entity_id='0';
  319.         else {
  320.             $msg->entity_id='1';
  321.         }
  322.         for ($i=0;$i<$iCnt;++$i{
  323.             $msg->entities[$i]->parent =$msg;
  324.             if (strrchr($msg->entity_id'.'!= '.0'{
  325.                 $msg->entities[$i]->setEntIds($msg->entities[$i],$msg->entity_id,$i);
  326.             else {
  327.                 $msg->entities[$i]->setEntIds($msg->entities[$i],$msg->parent->entity_id,$i);
  328.             }
  329.         }
  330.     }
  331.  
  332.     /**
  333.      * @param string $read 
  334.      * @param integer $i 
  335.      * @param mixed $sub_msg 
  336.      * @return object Message object
  337.      * @todo document me
  338.      * @since 1.4.0 (code was part of parseStructure() in 1.3.x)
  339.      */
  340.     function parseBodyStructure($read&$i$sub_msg ''{
  341.         $arg_no 0;
  342.         $arg_a  array();
  343.         if ($sub_msg{
  344.             $message $sub_msg;
  345.         else {
  346.             $message new Message();
  347.         }
  348.  
  349.         for ($cnt strlen($read)$i $cnt++$i{
  350.             $char strtoupper($read{$i});
  351.             switch ($char{
  352.                 case '(':
  353.                     switch($arg_no{
  354.                         case 0:
  355.                             if (!isset($msg)) {
  356.                                 $msg new Message();
  357.                                 $hdr new MessageHeader();
  358.                                 $hdr->type0 'text';
  359.                                 $hdr->type1 'plain';
  360.                                 $hdr->encoding 'us-ascii';
  361.                             else {
  362.                                 $msg->header->type0 'multipart';
  363.                                 $msg->type0 'multipart';
  364.                                 while ($read{$i== '('{
  365.                                     $msg->addEntity($msg->parseBodyStructure($read$i$msg));
  366.                                 }
  367.                             }
  368.                             break;
  369.                         case 1:
  370.                             /* multipart properties */
  371.                             ++$i;
  372.                             $arg_a[$msg->parseProperties($read$i);
  373.                             ++$arg_no;
  374.                             break;
  375.                         case 2:
  376.                             if (isset($msg->type0&& ($msg->type0 == 'multipart')) {
  377.                                 ++$i;
  378.                                 $arg_a[$msg->parseDisposition($read$i);
  379.                             else /* properties */
  380.                                 $arg_a[$msg->parseProperties($read$i);
  381.                             }
  382.                             ++$arg_no;
  383.                             break;
  384.                         case 3:
  385.                             if (isset($msg->type0&& ($msg->type0 == 'multipart')) {
  386.                                 ++$i;
  387.                                 $arg_a[]$msg->parseLanguage($read$i);
  388.                             }
  389.                         case 7:
  390.                             if (($arg_a[0== 'message'&& ($arg_a[1== 'rfc822')) {
  391.                                 $msg->header->type0 $arg_a[0];
  392.                                 $msg->header->type1 $arg_a[1];
  393.                                 $msg->type0 $arg_a[0];
  394.                                 $msg->type1 $arg_a[1];
  395.                                 $rfc822_hdr new Rfc822Header();
  396.                                 $msg->rfc822_header $msg->parseEnvelope($read$i$rfc822_hdr);
  397.                                 while (($i $cnt&& ($read{$i!= '(')) {
  398.                                     ++$i;
  399.                                 }
  400.                                 $msg->addEntity($msg->parseBodyStructure($read$i,$msg));
  401.                             }
  402.                             break;
  403.                         case 8:
  404.                             ++$i;
  405.                             $arg_a[$msg->parseDisposition($read$i);
  406.                             ++$arg_no;
  407.                             break;
  408.                         case 9:
  409.                             ++$i;
  410.                             if (($arg_a[0== 'text'|| (($arg_a[0== 'message'&& ($arg_a[1== 'rfc822'))) {
  411.                                 $arg_a[$msg->parseDisposition($read$i);
  412.                             else {
  413.                                 $arg_a[$msg->parseLanguage($read$i);
  414.                             }
  415.                             ++$arg_no;
  416.                             break;
  417.                        case 10:
  418.                            if (($arg_a[0== 'text'|| (($arg_a[0== 'message'&& ($arg_a[1== 'rfc822'))) {
  419.                                ++$i;
  420.                                $arg_a[$msg->parseLanguage($read$i);
  421.                            else {
  422.                                $i $msg->parseParenthesis($read$i);
  423.                                $arg_a[''/* not yet described in rfc2060 */
  424.                            }
  425.                            ++$arg_no;
  426.                            break;
  427.                        default:
  428.                            /* unknown argument, skip this part */
  429.                            $i $msg->parseParenthesis($read$i);
  430.                            $arg_a['';
  431.                            ++$arg_no;
  432.                            break;
  433.                    /* switch */
  434.                    break;
  435.                 case '"':
  436.                     /* inside an entity -> start processing */
  437.                     $arg_s $msg->parseQuote($read$i);
  438.                     ++$arg_no;
  439.                     if ($arg_no 3{
  440.                         $arg_s strtolower($arg_s)/* type0 and type1 */
  441.                     }
  442.                     $arg_a[$arg_s;
  443.                     break;
  444.                 case 'n':
  445.                 case 'N':
  446.                     /* probably NIL argument */
  447.                     $tmpnil strtoupper(substr($read$i4));
  448.                     if ($tmpnil == 'NIL ' || $tmpnil == 'NIL)'{
  449.                         $arg_a['';
  450.                         ++$arg_no;
  451.                         $i += 2;
  452.                     }
  453.                     break;
  454.                 case '{':
  455.                     /* process the literal value */
  456.                     $arg_a[$msg->parseLiteral($read$i);
  457.                     ++$arg_no;
  458.                     break;
  459.         case '0':
  460.                 case is_numeric($read{$i}):
  461.                     /* process integers */
  462.                     if ($read{$i== ' 'break}
  463.             ++$arg_no;
  464.             if (preg_match('/^([0-9]+).*/',substr($read,$i)$regs)) {
  465.                 $i += strlen($regs[1])-1;
  466.                 $arg_a[$regs[1];
  467.             else {
  468.                 $arg_a[0;
  469.             }
  470.                     break;
  471.                 case ')':
  472.                     $multipart (isset($msg->type0&& ($msg->type0 == 'multipart'));
  473.                     if (!$multipart{
  474.                         $shifted_args (($arg_a[0== 'text'|| (($arg_a[0== 'message'&& ($arg_a[1== 'rfc822')));
  475.                         $hdr->type0 $arg_a[0];
  476.                         $hdr->type1 $arg_a[1];
  477.  
  478.                         $msg->type0 $arg_a[0];
  479.                         $msg->type1 $arg_a[1];
  480.                         $arr $arg_a[2];
  481.                         if (is_array($arr)) {
  482.                             $hdr->parameters $arg_a[2];
  483.                         }
  484.                         $hdr->id str_replace('<'''str_replace('>'''$arg_a[3]));
  485.                         $hdr->description $arg_a[4];
  486.                         $hdr->encoding strtolower($arg_a[5]);
  487.                         $hdr->entity_id $msg->entity_id;
  488.                         $hdr->size $arg_a[6];
  489.                         if ($shifted_args{
  490.                             $hdr->lines $arg_a[7];
  491.                             $s 1;
  492.                         else {
  493.                             $s 0;
  494.                         }
  495.                         $hdr->md5 (isset($arg_a[7+$s]$arg_a[7+$s$hdr->md5);
  496.                         $hdr->disposition (isset($arg_a[8+$s]$arg_a[8+$s$hdr->disposition);
  497.                         $hdr->language (isset($arg_a[9+$s]$arg_a[9+$s$hdr->language);
  498.                         $msg->header $hdr;
  499.                     else {
  500.                         $hdr->type0 'multipart';
  501.                         $hdr->type1 $arg_a[0];
  502.                         $msg->type0 'multipart';
  503.                         $msg->type1 $arg_a[0];
  504.                         $hdr->parameters (isset($arg_a[1]$arg_a[1$hdr->parameters);
  505.                         $hdr->disposition (isset($arg_a[2]$arg_a[2$hdr->disposition);
  506.                         $hdr->language (isset($arg_a[3]$arg_a[3$hdr->language);
  507.                         $msg->header $hdr;
  508.                     }
  509.                     return $msg;
  510.                 defaultbreak;
  511.             /* switch */
  512.         /* for */
  513.     /* parsestructure */
  514.  
  515.     /**
  516.      * @param string $read 
  517.      * @param integer $i 
  518.      * @return array 
  519.      */
  520.     function parseProperties($read&$i{
  521.         $properties array();
  522.         $prop_name '';
  523.  
  524.         for ($read{$i!= ')'++$i{
  525.             $arg_s '';
  526.             if ($read{$i== '"'{
  527.                 $arg_s $this->parseQuote($read$i);
  528.             else if ($read{$i== '{'{
  529.                 $arg_s $this->parseLiteral($read$i);
  530.             }
  531.  
  532.             if ($arg_s != ''{
  533.                 if ($prop_name == ''{
  534.                     $prop_name strtolower($arg_s);
  535.                     $properties[$prop_name'';
  536.                 else if ($prop_name != ''{
  537.                     $properties[$prop_name$arg_s;
  538.                     $prop_name '';
  539.                 }
  540.             }
  541.         }
  542.         return $properties;
  543.     }
  544.  
  545.     /**
  546.      * @param string $read 
  547.      * @param integer $i 
  548.      * @param object $hdr MessageHeader object
  549.      * @return object MessageHeader object
  550.      */
  551.     function parseEnvelope($read&$i$hdr{
  552.         $arg_no 0;
  553.         $arg_a array();
  554.         ++$i;
  555.         for ($cnt strlen($read)($i $cnt&& ($read{$i!= ')')++$i{
  556.             $char strtoupper($read{$i});
  557.             switch ($char{
  558.                 case '"':
  559.                     $arg_a[$this->parseQuote($read$i);
  560.                     ++$arg_no;
  561.                     break;
  562.                 case '{':
  563.                     $arg_a[$this->parseLiteral($read$i);
  564.             /* temp bugfix (SM 1.5 will have a working clean version)
  565.                too much work to implement that version right now */
  566. //            --$i;
  567.                     ++$arg_no;
  568.                     break;
  569.                 case 'N':
  570.                     /* probably NIL argument */
  571.                     if (strtoupper(substr($read$i3)) == 'NIL'{
  572.                         $arg_a['';
  573.                         ++$arg_no;
  574.                         $i += 2;
  575.                     }
  576.                     break;
  577.                 case '(':
  578.                     /* Address structure (with group support)
  579.                      * Note: Group support is useless on SMTP connections
  580.                      *       because the protocol doesn't support it
  581.                      */
  582.                     $addr_a array();
  583.                     $group '';
  584.                     $a=0;
  585.                     for ($i $cnt && $read{$i!= ')'++$i{
  586.                         if ($read{$i== '('{
  587.                             $addr $this->parseAddress($read$i);
  588.                             if (($addr->host == ''&& ($addr->mailbox != '')) {
  589.                                 /* start of group */
  590.                                 $group $addr->mailbox;
  591.                                 $group_addr $addr;
  592.                                 $j $a;
  593.                             else if ($group && ($addr->host == ''&& ($addr->mailbox == '')) {
  594.                                /* end group */
  595.                                 if ($a == ($j+1)) /* no group members */
  596.                                     $group_addr->group $group;
  597.                                     $group_addr->mailbox '';
  598.                                     $group_addr->personal "$groupUndisclosed recipients;";
  599.                                     $addr_a[$group_addr;
  600.                                     $group ='';
  601.                                 }
  602.                             else {
  603.                                 $addr->group $group;
  604.                                 $addr_a[$addr;
  605.                             }
  606.                             ++$a;
  607.                         }
  608.                     }
  609.                     $arg_a[$addr_a;
  610.                     break;
  611.                 defaultbreak;
  612.             }
  613.         }
  614.  
  615.         if (count($arg_a9{
  616.             $d strtr($arg_a[0]array('  ' => ' '));
  617.             $d explode(' '$d);
  618.         if (!$arg_a[1]$arg_a[1_("(no subject)");
  619.  
  620.             $hdr->date getTimeStamp($d)/* argument 1: date */
  621.             $hdr->subject $arg_a[1];     /* argument 2: subject */
  622.             $hdr->from is_array($arg_a[2]$arg_a[2][0'';     /* argument 3: from        */
  623.             $hdr->sender is_array($arg_a[3]$arg_a[3][0'';   /* argument 4: sender      */
  624.             $hdr->replyto is_array($arg_a[4]$arg_a[4][0'';  /* argument 5: reply-to    */
  625.             $hdr->to $arg_a[5];          /* argument 6: to          */
  626.             $hdr->cc $arg_a[6];          /* argument 7: cc          */
  627.             $hdr->bcc $arg_a[7];         /* argument 8: bcc         */
  628.             $hdr->inreplyto $arg_a[8];   /* argument 9: in-reply-to */
  629.             $hdr->message_id $arg_a[9];  /* argument 10: message-id */
  630.         }
  631.         return $hdr;
  632.     }
  633.  
  634.     /**
  635.      * @param string $read 
  636.      * @param integer $i 
  637.      * @return string 
  638.      * @todo document me
  639.      */
  640.     function parseLiteral($read&$i{
  641.         $lit_cnt '';
  642.         ++$i;
  643.         $iPos strpos($read,'}',$i);
  644.         if ($iPos{
  645.             $lit_cnt substr($read$i$iPos $i);
  646.             $i += strlen($lit_cnt3/* skip } + \r + \n */
  647.             /* Now read the literal */
  648.             $s ($lit_cnt substr($read,$i,$lit_cnt)'');
  649.             $i += $lit_cnt;
  650.             /* temp bugfix (SM 1.5 will have a working clean version)
  651.                too much work to implement that version right now */
  652.             --$i;
  653.         else /* should never happen */
  654.             $i += 3/* } + \r + \n */
  655.             $s '';
  656.         }
  657.         return $s;
  658.     }
  659.  
  660.     /**
  661.      * @param string $read 
  662.      * @param integer $i 
  663.      * @return string 
  664.      * @todo document me
  665.      */
  666.     function parseQuote($read&$i{
  667.         $s '';
  668.         $iPos = ++$i;
  669.         while (true{
  670.             $iPos strpos($read,'"',$iPos);
  671.             if (!$iPosbreak;
  672.             if ($iPos && $read{$iPos -1!= '\\'{
  673.                 $s substr($read,$i,($iPos-$i));
  674.                 $i $iPos;
  675.                 break;
  676.             }
  677.             ++$iPos;
  678.             if ($iPos strlen($read)) {
  679.                 break;
  680.             }
  681.         }
  682.         return $s;
  683.     }
  684.  
  685.     /**
  686.      * @param string $read 
  687.      * @param integer $i 
  688.      * @return object AddressStructure object
  689.      */
  690.     function parseAddress($read&$i{
  691.         $arg_a array();
  692.         for ($read{$i!= ')'++$i{
  693.             $char strtoupper($read{$i});
  694.             switch ($char{
  695.                 case '"'$arg_a[$this->parseQuote($read$i)break;
  696.                 case '{'$arg_a[$this->parseLiteral($read$i)break;
  697.                 case 'n':
  698.                 case 'N':
  699.                     if (strtoupper(substr($read$i3)) == 'NIL'{
  700.                         $arg_a['';
  701.                         $i += 2;
  702.                     }
  703.                     break;
  704.                 defaultbreak;
  705.             }
  706.         }
  707.  
  708.         if (count($arg_a== 4{
  709.             $adr new AddressStructure();
  710.             $adr->personal $arg_a[0];
  711.             $adr->adl $arg_a[1];
  712.             $adr->mailbox $arg_a[2];
  713.             $adr->host $arg_a[3];
  714.         else {
  715.             $adr '';
  716.         }
  717.         return $adr;
  718.     }
  719.  
  720.     /**
  721.      * @param string $read 
  722.      * @param integer $i 
  723.      * @param object Disposition object or empty string
  724.      */
  725.     function parseDisposition($read&$i{
  726.         $arg_a array();
  727.         for ($read{$i!= ')'++$i{
  728.             switch ($read{$i}{
  729.                 case '"'$arg_a[$this->parseQuote($read$i)break;
  730.                 case '{'$arg_a[$this->parseLiteral($read$i)break;
  731.                 case '('$arg_a[$this->parseProperties($read$i)break;
  732.                 defaultbreak;
  733.             }
  734.         }
  735.  
  736.         if (isset($arg_a[0])) {
  737.             $disp new Disposition($arg_a[0]);
  738.             if (isset($arg_a[1])) {
  739.                 $disp->properties $arg_a[1];
  740.             }
  741.         }
  742.         return (is_object($disp$disp '');
  743.     }
  744.  
  745.     /**
  746.      * @param string $read 
  747.      * @param integer $i 
  748.      * @return object Language object or empty string
  749.      */
  750.     function parseLanguage($read&$i{
  751.         /* no idea how to process this one without examples */
  752.         $arg_a array();
  753.  
  754.         for ($read{$i!= ')'++$i{
  755.             switch ($read{$i}{
  756.                 case '"'$arg_a[$this->parseQuote($read$i)break;
  757.                 case '{'$arg_a[$this->parseLiteral($read$i)break;
  758.                 case '('$arg_a[$this->parseProperties($read$i)break;
  759.                 defaultbreak;
  760.             }
  761.         }
  762.  
  763.         if (isset($arg_a[0])) {
  764.             $lang new Language($arg_a[0]);
  765.             if (isset($arg_a[1])) {
  766.                 $lang->properties $arg_a[1];
  767.             }
  768.         }
  769.         return (is_object($lang$lang '');
  770.     }
  771.  
  772.     /**
  773.      * Parse message text enclosed in parenthesis
  774.      * @param string $read 
  775.      * @param integer $i 
  776.      * @return integer 
  777.      */
  778.     function parseParenthesis($read$i{
  779.         for ($read{$i!= ')'++$i{
  780.             switch ($read{$i}{
  781.                 case '"'$this->parseQuote($read$i)break;
  782.                 case '{'$this->parseLiteral($read$i)break;
  783.                 case '('$this->parseProperties($read$i)break;
  784.                 defaultbreak;
  785.             }
  786.         }
  787.         return $i;
  788.     }
  789.  
  790.     /**
  791.      * Function to fill the message structure in case the
  792.      * bodystructure is not available
  793.      * NOT FINISHED YET
  794.      * @param string $read 
  795.      * @param string $type0 message part type
  796.      * @param string $type1 message part subtype
  797.      * @return string (only when type0 is not message or multipart)
  798.      */
  799.     function parseMessage($read$type0$type1{
  800.         switch ($type0{
  801.             case 'message':
  802.                 $rfc822_header true;
  803.                 $mime_header false;
  804.                 break;
  805.             case 'multipart':
  806.                 $rfc822_header false;
  807.                 $mime_header true;
  808.                 break;
  809.             defaultreturn $read;
  810.         }
  811.  
  812.         for ($i 1$i $count++$i{
  813.             $line trim($body[$i]);
  814.             if (($mime_header || $rfc822_header&&
  815.                 (preg_match("/^.*boundary=\"?(.+(?=\")|.+).*/i"$line$reg))) {
  816.                 $bnd $reg[1];
  817.                 $bndreg $bnd;
  818.                 $bndreg str_replace("\\""\\\\"$bndreg);
  819.                 $bndreg str_replace("?""\\?"$bndreg);
  820.                 $bndreg str_replace("+""\\+"$bndreg);
  821.                 $bndreg str_replace(".""\\."$bndreg);
  822.                 $bndreg str_replace("/""\\/"$bndreg);
  823.                 $bndreg str_replace("-""\\-"$bndreg);
  824.                 $bndreg str_replace("(""\\("$bndreg);
  825.                 $bndreg str_replace(")""\\)"$bndreg);
  826.             else if ($rfc822_header && $line == ''{
  827.                 $rfc822_header false;
  828.                 if ($msg->type0 == 'multipart'{
  829.                     $mime_header true;
  830.                 }
  831.             }
  832.  
  833.             if ((($line{0== '-'|| $rfc822_header)  && isset($boundaries[0])) {
  834.                 $cnt count($boundaries)-1;
  835.                 $bnd $boundaries[$cnt]['bnd'];
  836.                 $bndreg $boundaries[$cnt]['bndreg'];
  837.  
  838.                 $regstr '/^--'."($bndreg)".".*".'/';
  839.                 if (preg_match($regstr$line$reg)) {
  840.                     $bndlen strlen($reg[1]);
  841.                     $bndend false;
  842.                     if (strlen($line($bndlen 3)) {
  843.                         if (($line{$bndlen+2== '-'&& ($line{$bndlen+3== '-')) {
  844.                             $bndend true;
  845.                         }
  846.                     }
  847.                     if ($bndend{
  848.                         /* calc offset and return $msg */
  849.                         //$entStr = CalcEntity("$entStr", -1);
  850.                         array_pop($boundaries);
  851.                         $mime_header true;
  852.                         $bnd_end true;
  853.                     else {
  854.                         $mime_header true;
  855.                          $bnd_end false;
  856.                         //$entStr = CalcEntity("$entStr", 0);
  857.                         ++$content_indx;
  858.                     }
  859.                 else {
  860.                     if ($header}
  861.                 }
  862.             }
  863.         }
  864.     }
  865.  
  866.     /**
  867.      * @param array $entity 
  868.      * @param array $alt_order 
  869.      * @param boolean $strict 
  870.      * @return array 
  871.      */
  872.     function findDisplayEntity($entity array()$alt_order array('text/plain''text/html')$strict=false{
  873.         $found false;
  874.         if ($this->type0 == 'multipart'{
  875.             if($this->type1 == 'alternative'{
  876.                 $msg $this->findAlternativeEntity($alt_order);
  877.                 if (count($msg->entities== 0{
  878.                     $entity[$msg->entity_id;
  879.                 else {
  880.                     $entity $msg->findDisplayEntity($entity$alt_order$strict);
  881.                 }
  882.                 $found true;
  883.             else if ($this->type1 == 'related'/* RFC 2387 */
  884.                 $msgs $this->findRelatedEntity();
  885.                 foreach ($msgs as $msg{
  886.                     if (count($msg->entities== 0{
  887.                         $entity[$msg->entity_id;
  888.                     else {
  889.                         $entity $msg->findDisplayEntity($entity$alt_order$strict);
  890.                     }
  891.                 }
  892.                 if (count($msgs0{
  893.                     $found true;
  894.                 }
  895.             else /* Treat as multipart/mixed */
  896.                 foreach ($this->entities as $ent{
  897.                     if(!(is_object($ent->header->disposition&& strtolower($ent->header->disposition->name== 'attachment'&&
  898.                             (!isset($ent->header->parameters['filename'])) &&
  899.                             (!isset($ent->header->parameters['name'])) &&
  900.                             (($ent->type0 != 'message'&& ($ent->type1 != 'rfc822'))) {
  901.                         $entity $ent->findDisplayEntity($entity$alt_order$strict);
  902.                         $found true;
  903.                     }
  904.                 }
  905.             }
  906.         else /* If not multipart, then just compare with each entry from $alt_order */
  907.             $type $this->type0.'/'.$this->type1;
  908. //        $alt_order[] = "message/rfc822";
  909.             foreach ($alt_order as $alt{
  910.                 if( ($alt == $type&& isset($this->entity_id) ) {
  911.                     if ((count($this->entities== 0&&
  912.                             (!isset($this->header->parameters['filename'])) &&
  913.                             (!isset($this->header->parameters['name'])) &&
  914.                             isset($this->header->disposition&& is_object($this->header->disposition&&
  915.                             !(is_object($this->header->disposition&& strtolower($this->header->disposition->name== 'attachment')) {
  916.                         $entity[$this->entity_id;
  917.                         $found true;
  918.                     }
  919.                 }
  920.             }
  921.         }
  922.         if(!$found{
  923.             foreach ($this->entities as $ent{
  924.                 if(!(is_object($ent->header->disposition&& strtolower($ent->header->disposition->name== 'attachment'&&
  925.                    (($ent->type0 != 'message'&& ($ent->type1 != 'rfc822'))) {
  926.                     $entity $ent->findDisplayEntity($entity$alt_order$strict);
  927.                     $found true;
  928.                 }
  929.             }
  930.         }
  931.         if(!$strict && !$found{
  932.             if (($this->type0 == 'text'&&
  933.                 in_array($this->type1array('plain''html''message')) &&
  934.                 isset($this->entity_id)) {
  935.                 if (count($this->entities== 0{
  936.                     if (!is_object($this->header->disposition|| strtolower($this->header->disposition->name!= 'attachment'{
  937.                         $entity[$this->entity_id;
  938.                     }
  939.                 }
  940.             }
  941.         }
  942.         return $entity;
  943.     }
  944.  
  945.     /**
  946.      * @param array $alt_order 
  947.      * @return array 
  948.      */
  949.     function findAlternativeEntity($alt_order{
  950.         /* If we are dealing with alternative parts then we  */
  951.         /* choose the best viewable message supported by SM. */
  952.         $best_view 0;
  953.         $entity array();
  954.         foreach($this->entities as $ent{
  955.             $type $ent->header->type0 '/' $ent->header->type1;
  956.             if ($type == 'multipart/related'{
  957.                 $type $ent->header->getParameter('type');
  958.             // Mozilla bug. Mozilla does not provide the parameter type.
  959.             if (!$type$type 'text/html';
  960.             }
  961.             $altCount count($alt_order);
  962.             for ($j $best_view$j $altCount++$j{
  963.                 if (($alt_order[$j== $type&& ($j >= $best_view)) {
  964.                     $best_view $j;
  965.                     $entity $ent;
  966.                 }
  967.             }
  968.         }
  969.         return $entity;
  970.     }
  971.  
  972.     /**
  973.      * @return array 
  974.      */
  975.     function findRelatedEntity({
  976.         $msgs array();
  977.         $related_type $this->header->getParameter('type');
  978.         // Mozilla bug. Mozilla does not provide the parameter type.
  979.         if (!$related_type$related_type 'text/html';
  980.         $entCount count($this->entities);
  981.         for ($i 0$i $entCount++$i{
  982.             $type $this->entities[$i]->header->type0.'/'.$this->entities[$i]->header->type1;
  983.             if ($related_type == $type{
  984.                 $msgs[$this->entities[$i];
  985.             }
  986.         }
  987.         return $msgs;
  988.     }
  989.  
  990.     /**
  991.      * @param array $exclude_id 
  992.      * @param array $result 
  993.      * @return array 
  994.      */
  995.     function getAttachments($exclude_id=array()$result array()) {
  996. /*
  997.         if (($this->type0 == 'message') &&
  998.         ($this->type1 == 'rfc822') &&
  999.         ($this->entity_id) ) {
  1000.             $this = $this->entities[0];
  1001.         }
  1002. */
  1003.         if (count($this->entities)) {
  1004.             foreach ($this->entities as $entity{
  1005.                 $exclude false;
  1006.                 foreach ($exclude_id as $excl{
  1007.                     if ($entity->entity_id === $excl{
  1008.                         $exclude true;
  1009.                     }
  1010.                 }
  1011.  
  1012.                 if (!$exclude{
  1013.                     if (($entity->type0 == 'multipart'&&
  1014.                         ($entity->type1 != 'related')) {
  1015.                         $result $entity->getAttachments($exclude_id$result);
  1016.                     else if ($entity->type0 != 'multipart'{
  1017.                         $result[$entity;
  1018.                     }
  1019.                 }
  1020.             }
  1021.         else {
  1022.             $exclude false;
  1023.             foreach ($exclude_id as $excl{
  1024.                 $exclude $exclude || ($this->entity_id == $excl);
  1025.             }
  1026.  
  1027.             if (!$exclude{
  1028.                 $result[$this;
  1029.             }
  1030.         }
  1031.         return $result;
  1032.     }
  1033.  
  1034.     /**
  1035.      * Add attachment to message object
  1036.      * @param string $type attachment type
  1037.      * @param string $name attachment name
  1038.      * @param string $location path to attachment
  1039.      */
  1040.     function initAttachment($type$name$location{
  1041.         $attachment new Message();
  1042.         $mime_header new MessageHeader();
  1043.         $mime_header->setParameter('name'$name);
  1044.         // FIXME: duplicate code. see ContentType class
  1045.         $pos strpos($type'/');
  1046.         if ($pos 0{
  1047.             $mime_header->type0 substr($type0$pos);
  1048.             $mime_header->type1 substr($type$pos+1);
  1049.         else {
  1050.             $mime_header->type0 $type;
  1051.         }
  1052.         $attachment->att_local_name $location;
  1053.         $disposition new Disposition('attachment');
  1054.         $disposition->properties['filename'$name;
  1055.         $mime_header->disposition $disposition;
  1056.         $attachment->mime_header $mime_header;
  1057.         $this->entities[]=$attachment;
  1058.     }
  1059.  
  1060.     /**
  1061.      * Delete all attachments from this object from disk.
  1062.      * @since 1.5.1
  1063.      */
  1064.     function purgeAttachments({
  1065.         if ($this->att_local_name && file_exists($this->att_local_name)) {
  1066.             unlink($this->att_local_name);
  1067.         }
  1068.         // recursively delete attachments from entities contained in this object
  1069.         for ($i=0$entCount=count($this->entities);$i$entCount++$i{
  1070.             $this->entities[$i]->purgeAttachments();
  1071.         }
  1072.     }
  1073. }

Documentation generated on Sat, 07 Oct 2006 16:12:26 +0300 by phpDocumentor 1.3.0RC6