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, stekkel@users.sourceforge.net)
  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];
    <