Mail_IMAPv2
[ class tree: Mail_IMAPv2 ] [ index: Mail_IMAPv2 ] [ all elements ]

Source for file IMAPv2.php

Documentation is available at IMAPv2.php

  1. <?php
  2.  
  3. //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  4. //\\\       \\\\\\\\|                                                      \\
  5. //\\\ @@    @@\\\\\\| Mail_IMAPv2                                          \\
  6. //\\ @@@@  @@@@\\\\\|______________________________________________________\\
  7. //\\\@@@@| @@@@\\\\\|                                                      \\
  8. //\\\ @@ |\\@@\\\\\\|(c) Copyright 2004 Richard York, All rights Reserved  \\
  9. //\\\\  ||   \\\\\\\|______________________________________________________\\
  10. //\\\\  \\_   \\\\\\|Redistribution and use in source and binary forms,    \\
  11. //\\\\\        \\\\\|with or without modification, are permitted provided  \\
  12. //\\\\\  ----  \@@@@|that the following conditions are met:                \\
  13. //@@@@@\       \@@@@|                                                      \\
  14. //@@@@@@\     \@@@@@| o Redistributions of source code must retain the     \\
  15. //\\\\\\\\\\\\\\\\\\|  above copyright notice, this list of conditions and \\
  16. //    the following disclaimer.                                            \\
  17. //  o Redistributions in binary form must reproduce the above copyright    \\
  18. //    notice, this list of conditions and the following disclaimer in the  \\
  19. //    documentation and/or other materials provided with the distribution. \\
  20. //  o The names of the authors may not be used to endorse or promote       \\
  21. //    products derived from this software without specific prior written   \\
  22. //    permission.                                                          \\
  23. //                                                                         \\
  24. //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS    \\
  25. //  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT      \\
  26. //  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR  \\
  27. //  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT   \\
  28. //  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  \\
  29. //  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT       \\
  30. //  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,  \\
  31. //  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY  \\
  32. //  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT    \\
  33. //  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  \\
  34. //  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   \\
  35. //\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
  36.  
  37. require_once 'PEAR/ErrorStack.php';
  38.  
  39. define('Mail_IMAPv2_BODY',                                0);
  40. define('Mail_IMAPv2_LITERAL',                             1);
  41. define('Mail_IMAPv2_LITERAL_DECODE',                      2);
  42.  
  43. define('Mail_IMAPv2_ERROR',                               1);
  44. define('Mail_IMAPv2_ERROR_ARGUMENT_REQUIRES_ARRAY',       2);
  45. define('Mail_IMAPv2_ERROR_INVALID_OPTION',                3);
  46. define('Mail_IMAPv2_ERROR_INVALID_PID',                   4);
  47. define('Mail_IMAPv2_ERROR_INVALID_ACTION',                5);
  48.  
  49. define('Mail_IMAPv2_NOTICE',                              100);
  50. define('Mail_IMAPv2_NOTICE_FALLBACK_PID',                 102);
  51.  
  52. define('Mail_IMAPv2_FATAL',                               200);
  53.  
  54. /**
  55. * Mail_IMAPv2 provides a flexible API for connecting to and retrieving
  56. * mail from mailboxes using the IMAP, POP3 or NNTP mail protocols.
  57. * Connection to a mailbox is acheived through the c-client extension
  58. * to PHP (http://www.php.net/imap). Meaning installation of the
  59. * c-client extension is required to use Mail_IMAPv2.
  60. *
  61. * Mail_IMAPv2 can be used to retrieve the contents of a mailbox,
  62. * whereas it may serve as the backend for a webmail application or
  63. * mailing list manager.
  64. *
  65. * Since Mail_IMAPv2 is an abstracted object, it allows for complete
  66. * customization of the UI for any application.
  67. *
  68. * By default Mail_IMAPv2 parses and retrieves information about
  69. * multipart message in a threaded fashion similar to MS Outlook, e.g.
  70. * only top level attachments are retrieved initially, then when message
  71. * part id and message id are passed to Mail_IMAPv2, it retrieves
  72. * attachments and information relevant to that message part.
  73. {@link getParts} can be supplied an argument to turn off threading,
  74. * whereas all parts are retrieved at once.
  75. *
  76. * Mail_IMAPv2 also, by default retrieves the alternative message parts
  77. * of multipart messages. This is most useful for debugging
  78. * applications that send out multipart mailers where both a text/html
  79. * and alterntaive text/plain part are included. This can also be
  80. * turned off by supplying an additional argument to {@link getParts}.
  81. *
  82. * Mail_IMAPv2 always searches for a text/html part to display as the primary
  83. * part. This can be reversed so that it always looks for a text/plain part
  84. * initially by supplying the necessary arguments to {@link getParts},
  85. * and {@link getBody}.
  86. *
  87. * PLEASE REPORT BUGS FOLLOWING THE GUIDELINES AT:
  88. *   http://www.smilingsouls.net/Mail_IMAP
  89. *
  90. @author       Richard York <rich_y@php.net>
  91. @category     Mail
  92. @package      Mail_IMAPv2
  93. @license      BSD
  94. @version      0.1.0
  95. @copyright    (c) Copyright 2004, Richard York, All Rights Reserved.
  96. @since        PHP 4.2.0
  97. @since        C-Client 2001
  98. @tutorial     http://www.smilingsouls.net/Mail_IMAP
  99. *
  100. @example      docs/examples/IMAP.inbox.php
  101. *    Mail_IMAPv2 Inbox
  102. *
  103. @example      docs/examples/IMAP.message_viewer.php
  104. *    Mail_IMAPv2 Message
  105. *
  106. @example      docs/examples/IMAP.part_viewer.php
  107. *    Mail_IMAPv2 Message
  108. *
  109. @example      docs/examples/IMAP.connection_wizard.php
  110. *    Mail_IMAPv2 Connection Wizard
  111. *
  112. @example      docs/examples/IMAP.connection_wizard_example.php
  113. *    Mail_IMAPv2 Connection Wizard
  114. */
  115. class Mail_IMAPv2 {
  116.  
  117.     /**
  118.      * Contains an instance of the PEAR_ErrorStack object.
  119.      * @var      object $error 
  120.      * @access   public
  121.      * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/error
  122.      */
  123.     var $error;
  124.  
  125.     /**
  126.      * Contains the imap resource stream.
  127.      * @var     resource $mailbox 
  128.      * @access  public
  129.      * @see     Mail_IMAPv2
  130.      * @see     open
  131.      * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/mailbox
  132.      */
  133.     var $mailbox;
  134.  
  135.     /**
  136.      * Contains information about the current mailbox.
  137.      * @var     array $mailboxInfo 
  138.      * @access  public
  139.      * @see     connect
  140.      * @see     getMailboxInfo
  141.      * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/mailboxInfo
  142.      */
  143.     var $mailboxInfo = array();
  144.  
  145.     /**
  146.      * Set flags for various imap_* functions.
  147.      *
  148.      * Use associative indices to indicate the imap_* function to set flags for,
  149.      *  create the indice omitting the 'imap_' portion of the function name.
  150.      *  see: {@link setOptions} for more information.
  151.      *
  152.      * @var     array $option 
  153.      * @access  public
  154.      * @see     setOptions
  155.      * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/setOptions
  156.      */
  157.     var $option = array();
  158.  
  159.     /**
  160.      * Contains various information returned by {@link imap_fetchstructure}.
  161.      * The object returned by imap_fetchstructure stored in $this->structure[$mid]['obj'].
  162.      *
  163.      * @var     array $_structure 
  164.      * @access  public
  165.      * @see     _declareParts
  166.      * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/structure
  167.      */
  168.     var $structure = array();
  169.  
  170.     /**
  171.      * Contains various information about a message, separates inline parts from
  172.      * attachments and contains the default part id for each message.
  173.      *
  174.      * @var     array $msg 
  175.      * @access  public
  176.      * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/msg
  177.      */
  178.     var $msg = array();
  179.  
  180.     /**
  181.      * (array)(mixed) Associative array containing information
  182.      * gathered by {@link imap_headerinfo} or
  183.      * {@link imap_rfc822_parse_headers}.
  184.      *
  185.      * @var    header array $header
  186.      * @see     getHeaders
  187.      * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/header
  188.      */
  189.  
  190.     var $header = array();
  191.  
  192.     /**
  193.      * (string) contains the various possible data types.
  194.      * @var     array $_dataTypes 
  195.      * @access  private
  196.      * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_dataTypes
  197.      */
  198.     var $_dataTypes = array('text',
  199.                             'multipart',
  200.                             'message',
  201.                             'application',
  202.                             'audio',
  203.                             'image',
  204.                             'video',
  205.                             'other');
  206.  
  207.     /**
  208.      * (string) Contains the various possible encoding types.
  209.      * @var     array $_encodingTypes 
  210.      * @access  private
  211.      * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_encodingTypes
  212.      */
  213.     var $_encodingTypes = array('7bit',
  214.                                 '8bit',
  215.                                 'binary',
  216.                                 'base64',
  217.                                 'quoted-printable',
  218.                                 'other');
  219.  
  220.     /**
  221.      * (string) Contains the fields searched for and added to inline and attachment part
  222.      * arrays. These are the 'in' and 'at' associative indices of the $msg member variable.
  223.      * @var    array $fields 
  224.      * @access public
  225.      * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/fields
  226.      */
  227.     var $fields = array('fname',
  228.                         'pid',
  229.                         'ftype',
  230.                         'fsize',
  231.                         'has_at',
  232.                         'charset',
  233.                         'cid');
  234.  
  235.     /**
  236.     * Constructor. Optionally set the IMAP resource stream.
  237.     *
  238.     * If IMAP connection arguments are not supplied, returns null.  Accepts a URI
  239.     * abstraction of the standard imap_open connection argument (see {@link connect})
  240.     * or the imap resource indicator.
  241.     *
  242.     * If the optional flags argument of imap_open needs to be set, then {@link connect}
  243.     * should be called after either setting the {@link $option} member variable or
  244.     * calling {@link setOptions}.
  245.     *
  246.     * Since Mail_IMAPv2 0.1.0 creates an instance of PEAR_ErrorStack.
  247.     *  $options argument became $get_info argument see {@link connect}.
  248.     *
  249.     * @param     string         $connection  (optional) server URI | imap resource identifier
  250.     * @param     int            $action 
  251.     *
  252.     * @tutorial  http://www.smilingsouls.net/?content=Mail_IMAP/Mail_IMAP
  253.     * @access    public
  254.     * @return    BOOL|null|PEAR_Error
  255.     * @see       connect
  256.     * @see       imap_open
  257.     */
  258.     function Mail_IMAPv2($connection = null$get_info = true)
  259.     {
  260.         $this->error = new PEAR_ErrorStack('Mail_IMAPv2');
  261.  
  262.         if (!empty($connection&& is_resource($connection)) {
  263.             if (get_resource_type($connection== 'imap'{
  264.                 $this->mailbox = $connection;
  265.             else {
  266.                 $this->error->push(Mail_IMAPv2_ERROR'error'null'Invalid imap resource passed to constructor.');
  267.             }
  268.         else if (!empty($connection)) {
  269.             $this->connect($connection$get_info);
  270.         }
  271.     }
  272.  
  273.     /**
  274.     * @todo Finish writing this method, and test it.
  275.     */
  276.     function errorTemplate()
  277.     {
  278.         return array(
  279.             // Generic Error
  280.             Mail_IMAPv2_ERROR                            => '%message%',
  281.             Mail_IMAPv2_ERROR_ARGUMENT_REQUIRES_ARRAY    => 'Argument \'%arg%\' must be an array.',
  282.             Mail_IMAPv2_ERROR_INVALID_OPTION            => 'Indice \'%indice%\' for argument \'%arg%\' is not a valid option.',
  283.             Mail_IMAPv2_ERROR_INVALID_PID                => 'Supplied part id \'%pid%\' is not valid.',
  284.             Mail_IMAPv2_ERROR_INVALID_ACTION            => 'Action \'%action%\' is not a valid action for the \'%arg%\' argument.',
  285.             Mail_IMAPv2_NOTICE_FALLBACK_PID                => 'Fallback PID used. A fallback PID is used in the event that Mail_IMAPv2 is not able to find a valid text/plain or text/html message part. The MIME type for the fallback pid is %ftype%'
  286.         );
  287.     }
  288.  
  289.     /**
  290.     * Wrapper method for {@link imap_open}.  Accepts a URI abstraction in
  291.     * the following format: imap://user:pass@mail.example.com:143/INBOX#notls
  292.     * instead of the standard connection arguments used in imap_open.
  293.     * Replace the protocol with one of pop3|pop3s imap|imaps nntp|nntps.
  294.     * Place intial folder in the file path portion, and optionally append
  295.     * tls|notls|novalidate-cert in the anchor portion of the URL.  A port
  296.     * number is optional, however, leaving it off could lead to a serious
  297.     * degradation in preformance.
  298.     *
  299.     * Since Mail_IMAPv2 0.1.0 the $options argument became the $get_info argument.
  300.     * constants for action were removed and the argument is now a BOOL toggle.
  301.     *
  302.     * @param    string           $uri   server URI
  303.     * @param    bool             $get_info 
  304.     *    (optional) true by default. If true, make a call to {@link getMailboxInfo}
  305.     *    if false do not call {@link getMailboxInfo}
  306.     * @return   BOOL 
  307.     * @tutorial http://www.smilingsouls.net/index.php?content=Mail_IMAP/connect
  308.     * @access   public
  309.     * @see      imap_open
  310.     */
  311.     function connect($uri$get_info = true)
  312.     {
  313.         if (!class_exists('Net_URL')) {
  314.             if (!@include_once('Net/URL.php')) {
  315.                 $this->error->push(Mail_IMAPv2_ERROR'error'null'Inclusion of Net_URL not successful.');
  316.                 return false;
  317.             }
  318.         }
  319.  
  320.         $opt (isset($this->option['open']))$this->option['open': null;
  321.  
  322.         $net_url =new Net_URL($uri);
  323.  
  324.         $uri  '{'.$net_url->host;
  325.  
  326.         if (!empty($net_url->port)) {
  327.             $uri .= ':'.$net_url->port;
  328.         }
  329.  
  330.         $secure   ('tls' == substr($net_url->anchor03))'' '/ssl';
  331.         $uri .= ('s' == (substr($net_url->protocol-1)))'/'.substr($net_url->protocol04).$secure '/'.$net_url->protocol;
  332.  
  333.         if (!empty($net_url->anchor)) {
  334.             $uri .= '/'.$net_url->anchor;
  335.         }
  336.  
  337.         $uri .= '}';
  338.  
  339.         $this->mailboxInfo['Mail_IMAPv2']['version''Mail_IMAPv2 0.1.0 Beta';
  340.         $this->mailboxInfo['host'$uri;
  341.  
  342.         // Trim off the leading slash '/'
  343.         if (!empty($net_url->path)) {
  344.             $this->mailboxInfo['folder'substr($net_url->path1(strlen($net_url->path- 1));
  345.             $uri .= $this->mailboxInfo['folder'];
  346.         }
  347.  
  348.         $this->mailboxInfo['user'urldecode($net_url->user);
  349.  
  350.         if (false === ($this->mailbox = @imap_open($uriurldecode($net_url->user)$net_url->pass$opt))) {
  351.             $this->error->push(Mail_IMAPv2_ERROR'error'null'Unable to build a connection to the specified mail server.');
  352.             $ret = false;
  353.         else {
  354.             $ret = true;
  355.         }
  356.  
  357.         // get mailbox info
  358.         if ($get_info == true{
  359.             $this->getMailboxInfo(false);
  360.         }
  361.  
  362.         return $ret;
  363.     }
  364.  
  365.     /*
  366.     * Adds to the {@link $mailboxInfo} member variable information about the current
  367.     * mailbox from {@link imap_mailboxmsginfo}.
  368.     *
  369.     * Note: This method is automatically called on by default by {@link connect}.
  370.     *
  371.     * @param    string           $connect   server URL
  372.     * @param    bool             $get_info
  373.     *   (optional) true by default. If true, make a call to {@link getMailboxInfo}
  374.     *   if false do not call {@link getMailboxInfo}
  375.     *
  376.     * @return   VOID|Array
  377.     * @access   public
  378.     * @see      imap_open
  379.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/getMailboxInfo
  380.     */
  381.     function getMailboxInfo($ret = true)
  382.     {
  383.         // It's possible that this function has already been called by $this->connect
  384.         // If so, the 'Mailbox' indice will already exist and the user just wants
  385.         // the contents of the mailboxInfo member variable.
  386.         if (!isset($this->mailboxInfo['Mailbox'])) {
  387.             $this->mailboxInfo = @array_merge($this->mailboxInfoget_object_vars(imap_mailboxmsginfo($this->mailbox)));
  388.         }
  389.  
  390.         if ($ret{
  391.             return $this->mailboxInfo;
  392.         else {
  393.             return true;
  394.         }
  395.     }
  396.  
  397.     /**
  398.     * Set the $option member variable, which is used to specify optional imap_* function
  399.     * arguments (labeled in the manual as flags or options e.g. FT_UID, OP_READONLY, etc).
  400.     *
  401.     * <b>Example:</b>
  402.     * <code>
  403.     *    $msg->setOptions(array('body', 'fetchbody', 'fetchheader'), 'FT_UID');
  404.     * </code>
  405.     *
  406.     * This results in imap_body, imap_fetchbody and imap_fetchheader being passed the FT_UID
  407.     * option in the flags/options argument where ever these are called on by Mail_IMAPv2.
  408.     *
  409.     * Note: this method only sets optional imap_* arguments labeled as flags/options.
  410.     *
  411.     * @param    array          $options - function names to pass the arugument to
  412.     * @param    string         $constant   - constant name to pass.
  413.     * @return   PEAR_Error|true
  414.     * @access   public
  415.     * @see      $option
  416.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/setOptions
  417.     */
  418.     function setOptions($options$constant)
  419.     {
  420.         if (is_array($options&& !empty($options)) {
  421.             foreach ($options as $value{
  422.                 if (!$this->option[$value@constant($constant)) {
  423.                     $this->error->push(Mail_IMAPv2_ERROR'error'null'The constant: '.$constant.' is not defined!');
  424.                 }
  425.             }
  426.         else {
  427.             $this->error->push(Mail_IMAPv2_ERROR_ARGUMENT_REQUIRES_ARRAY'error'array('arg' => '$options'));
  428.             return false;
  429.         }
  430.         return true;
  431.     }
  432.  
  433.     /**
  434.     * Wrapper method for {@link imap_close}.  Close the IMAP resource stream.
  435.     *
  436.     * @return   BOOL 
  437.     * @access   public
  438.     * @tutorial http://www.smilingsouls.net/index.php?content=Mail_IMAP/close
  439.     * @see      imap_close
  440.     */
  441.     function close()
  442.     {
  443.         $opt (isset($this->option['close']))$this->option['close': null;
  444.         return @imap_close($this->mailbox$opt);
  445.     }
  446.  
  447.     /**
  448.     * Wrapper method for {@link imap_num_msg}.
  449.     *
  450.     * @return   int mailbox message count
  451.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/messageCount
  452.     * @access   public
  453.     * @see      imap_num_msg
  454.     */
  455.     function messageCount()
  456.     {
  457.         return @imap_num_msg($this->mailbox);
  458.     }
  459.  
  460.     /**
  461.     * Gather message information returned by {@link imap_fetchstructure} and recursively iterate
  462.     * through each parts array.  Concatenate part numbers in the following format `1.1`
  463.     * each part id is separated by a period, each referring to a part or subpart of a
  464.     * multipart message.  Create part numbers as such that they are compatible with
  465.     * {@link imap_fetchbody}.
  466.     *
  467.     * @param    int           &$mid         message id
  468.     * @param    array         $sub_part     recursive
  469.     * @param    string        $sub_pid      recursive parent part id
  470.     * @param    int           $n            recursive counter
  471.     * @param    bool          $is_sub_part  recursive
  472.     * @param    bool          $skip_part    recursive
  473.     * @return   mixed 
  474.     * @access   protected
  475.     * @see      imap_fetchstructure
  476.     * @see      imap_fetchbody
  477.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_declareParts
  478.     */
  479.     function _declareParts(&$mid$sub_part = null$sub_pid = null$n = 0$is_sub_part = false$skip_part = false$last_was_signed = false)
  480.     {
  481.         if (!is_array($sub_part)) {
  482.             $opt (isset($this->option['fetchstructure']))$this->option['fetchstructure': null;
  483.             $this->structure[$mid]['obj'@imap_fetchstructure($this->mailbox$mid$opt);
  484.         }
  485.  
  486.         if (isset($this->structure[$mid]['obj']->parts|| is_array($sub_part)) {
  487.  
  488.             if (!$is_sub_part{
  489.                 $parts $this->structure[$mid]['obj']->parts;
  490.             else {
  491.                 $parts $sub_part;
  492.                 $n++;
  493.             }
  494.  
  495.             for ($p = 0$i = 1; $p count($parts)$n++$p++$i++{
  496.                 // Skip the following...
  497.                 // multipart/mixed!
  498.                 // subsequent multipart/alternative if this part is message/rfc822
  499.                 // multipart/related
  500.                 //
  501.                 // Have noticed the existence of several other multipart/* types of messages
  502.                 // but have yet had the opportunity to test on those.
  503.                 $ftype        (empty($parts[$p]->type))?
  504.                     $this->_dataTypes[0].'/'.strtolower($parts[$p]->subtype$this->_dataTypes[$parts[$p]->type].'/'.strtolower($parts[$p]->subtype);
  505.  
  506.                 $this_was_signed    ($ftype == 'multipart/signed')? true : false;
  507.                 $skip_next            ($ftype == 'message/rfc822')?   true : false;
  508.  
  509.                 if $ftype == 'multipart/mixed' && $last_was_signed ||
  510.                      $ftype == 'multipart/signed' || 
  511.                      $skip_part && $ftype == 'multipart/alternative' ||
  512.                      $ftype == 'multipart/related' && count($parts== 1
  513.                    {
  514.                     $n--;
  515.                     $skipped = true;
  516.                 else {
  517.                     $skipped = false;
  518.  
  519.                     $this->structure[$mid]['pid'][$n($is_sub_part == false)? (string) "$i" : (string) "$sub_pid.$i";
  520.  
  521.                     $this->structure[$mid]['ftype'][$n]     $ftype;
  522.                     $this->structure[$mid]['encoding'][$n]  (empty($parts[$p]->encoding))$this->_encodingTypes[0$this->_encodingTypes[$parts[$p]->encoding];
  523.                     $this->structure[$mid]['fsize'][$n]     (!isset($parts[$p]->bytes|| empty($parts[$p]->bytes))? 0 : $parts[$p]->bytes;
  524.  
  525.                     // Get extra parameters.
  526.                     if ($parts[$p]->ifparameters{
  527.                          foreach ($parts[$p]->parameters as $param{
  528.                              $this->structure[$mid][strtolower($param->attribute)][$nstrtolower($param->value);
  529.                         }
  530.                     }
  531.  
  532.                     // Force inline disposition if none is present
  533.                     if ($parts[$p]->ifdisposition{
  534.                         $this->structure[$mid]['disposition'][$nstrtolower($parts[$p]->disposition);
  535.                         if ($parts[$p]->ifdparameters{
  536.                             foreach ($parts[$p]->dparameters as $param{
  537.                                 if (strtolower($param->attribute== 'filename'{
  538.                                     $this->structure[$mid]['fname'][$n$param->value;
  539.                                     break;
  540.                                 }
  541.                             }
  542.                         }
  543.                     else {
  544.                         $this->structure[$mid]['disposition'][$n'inline';
  545.                     }
  546.  
  547.                     if ($parts[$p]->ifid{
  548.                         $this->structure[$mid]['cid'][$n$parts[$p]->id;
  549.                     }
  550.                 }
  551.  
  552.                 if (isset($parts[$p]->parts&& is_array($parts[$p]->parts)) {
  553.                     if (!$skipped{
  554.                         $this->structure[$mid]['has_at'][$n= true;
  555.                     }
  556.  
  557.                     $n $this->_declareParts($mid$parts[$p]->parts$this->structure[$mid]['pid'][$n]$ntrue$skip_next$this_was_signed);
  558.  
  559.                 else if (!$skipped{
  560.                     $this->structure[$mid]['has_at'][$n= false;
  561.                 }
  562.             }
  563.  
  564.             if ($is_sub_part{
  565.                 return $n;
  566.             }
  567.  
  568.          else {
  569.              // $parts is not an array... message is flat
  570.             $this->structure[$mid]['pid'][0= 1;
  571.  
  572.             if (empty($this->structure[$mid]['obj']->type)) {
  573.                 $this->structure[$mid]['obj']->type = (int) 0;
  574.             }
  575.  
  576.             if (isset($this->structure[$mid]['obj']->subtype)) {
  577.                 $this->structure[$mid]['ftype'][0$this->_dataTypes[$this->structure[$mid]['obj']->type].'/'.strtolower($this->structure[$mid]['obj']->subtype);
  578.             }
  579.  
  580.             if (empty($this->structure[$mid]['obj']->encoding)) {
  581.                 $this->structure[$mid]['obj']->encoding = (int) 0;
  582.             }
  583.  
  584.             $this->structure[$mid]['encoding'][0$this->_encodingTypes[$this->structure[$mid]['obj']->encoding];
  585.  
  586.             if (isset($this->structure[$mid]['obj']->bytes)) {
  587.                 $this->structure[$mid]['fsize'][0strtolower($this->structure[$mid]['obj']->bytes);
  588.             }
  589.  
  590.             $this->structure[$mid]['disposition'][0]    'inline';
  591.             $this->structure[$mid]['has_at'][0= false;
  592.  
  593.             // Go through the parameters, if any
  594.             if (isset($this->structure[$mid]['obj']->ifparameters&& $this->structure[$mid]['obj']->ifparameters{
  595.                 foreach ($this->structure[$mid]['obj']->parameters as $param{
  596.                     $this->structure[$mid][strtolower($param->attribute)][0$param->value;
  597.                 }
  598.             }
  599.         }
  600.  
  601.         return;
  602.     }
  603.  
  604.     /**
  605.     * Checks if the part has been parsed, if not calls on _declareParts to
  606.     * parse the message.
  607.     *
  608.     * @param    int          &$mid         message id
  609.     * @param    bool         $checkPid 
  610.     * @return   void 
  611.     * @access   protected
  612.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_checkIfParsed
  613.     */
  614.     function _checkIfParsed(&$mid$checkPid = true$get_mime 'text/html')
  615.     {
  616.         if (!isset($this->structure[$mid]['pid'])) {
  617.            $this->_declareParts($mid);
  618.         }
  619.  
  620.         if ($checkPid == true && !isset($this->msg[$mid]['pid'])) {
  621.            $this->_getDefaultPid($mid$get_mime);
  622.         }
  623.         return;
  624.     }
  625.  
  626.     /**
  627.     * sets up member variables containing inline parts and attachments for a specific
  628.     * part in member variable arrays beginning with 'in' and 'attach'. If inline parts
  629.     * are present, sets {@link $inPid}{@link $inFtype}{@link $inFsize},
  630.     * {@link $inHasAttach}{@link $inInlineId} (if an inline CID is specified). If
  631.     * attachments are present, sets, {@link $attachPid}{@link $attachFsize},
  632.     * {@link $attachHasAttach}{@link $attachFname} (if a filename is present, empty
  633.     * string otherwise).
  634.     *
  635.     * @param    int           &$mid         message id
  636.     * @param    int           &$pid         part id
  637.     * @param    bool          $ret 
  638.     *    false by default, if true returns the contents of the $in* and $attach* arrays.
  639.     *    If false method returns BOOL.
  640.     *
  641.     * @param    string        $args         (optional)
  642.     *    Associative array containing optional extra arguments. The following are the
  643.     *    possible indices.
  644.     *
  645.     *        $args['get_mime'] STRING
  646.     *            Values: text/plain|text/html, text/html by default. The MIME type for
  647.     *            the part to be displayed by default for each level of nesting.
  648.     *
  649.     *        $agrs['get_alternative'] BOOL
  650.     *            If true, includes the alternative part of a multipart/alternative
  651.     *            message in the $in* array. If veiwing text/html part by default this
  652.     *            places the text/plain part in the $in* (inline attachment array).
  653.     *
  654.     *        $args['retrieve_all'] BOOL
  655.     *            If true, gets all the message parts at once, this option will index
  656.     *            the entire message in the $in* and $attach* member variables regardless
  657.     *            of nesting (method indexes parts relevant to the current level of
  658.     *            nesting by default).
  659.     *
  660.     * @return   BOOL|Array
  661.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/getParts
  662.     * @access   public
  663.     * @since    PHP 4.2.0
  664.     */
  665.     function getParts(&$mid$pid '0'$ret = false$args = array())
  666.     {
  667.         if (!isset($args['get_mime'])) {
  668.             $args['get_mime''text/html';
  669.         }
  670.  
  671.         if (!isset($args['get_alternative'])) {
  672.             $args['get_alternative'= true;
  673.         }
  674.  
  675.         $this->_checkIfParsed($midtrue$args['get_mime']);
  676.  
  677.         if ($pid == '0'{
  678.             $pid $this->msg[$mid]['pid'];
  679.         }
  680.  
  681.         if (count($this->structure[$mid]['pid']== 1 && !isset($this->structure[$mid]['fallback'][0])) {
  682.             return true;
  683.         }
  684.  
  685.         // retrieve key for this part, so that the information may be accessed
  686.         if (false !== ($i array_search((string) $pid$this->structure[$mid]['pid']))) {
  687.             if (isset($args['retrieve_all']&& $args['retrieve_all'== true{
  688.                 $this->_scanMultipart($mid$pid$i$args['get_mime']'add''none'2$args['get_alternative']);
  689.             else {
  690.                 if ($pid == $this->msg[$mid]['pid']{
  691.                     $this->_scanMultipart($mid$pid$i$args['get_mime']'add''top'2$args['get_alternative']);
  692.                 else if ($this->structure[$mid]['ftype'][$i== 'message/rfc822'{
  693.                     $this->_scanMultipart($mid$pid$i$args['get_mime']'add''all'1$args['get_alternative']);
  694.                 }
  695.             }
  696.         else {
  697.             $this->error->push(Mail_IMAPv2_ERROR_INVALID_PID'error'array('pid' => $pid));
  698.             return false;
  699.         }
  700.  
  701.         if ($ret == true{
  702.             return $this->msg[$mid];
  703.         else {
  704.             return true;
  705.         }
  706.     }
  707.  
  708.     /**
  709.     * Finds message parts relevant to the message part currently being displayed or
  710.     * looks through a message and determines which is the best body to display.
  711.     *
  712.     * @param    int           &$mid         message id
  713.     * @param    int           &$pid         part id
  714.     * @param    int           $i            offset indice correlating to the pid
  715.     * @param    str           $MIME         one of text/plain or text/html the default MIME to retrieve.
  716.     * @param    str           $action       one of add|get
  717.     * @param    str           $look_for     one of all|multipart|top|none
  718.     * @param    int           $pid_add      determines the level of nesting.
  719.     * @param    bool          $get_alternative 
  720.     *    Determines whether the program retrieves the alternative part in a
  721.     *    multipart/alternative message.
  722.     *
  723.     * @return   string|false
  724.     * @access   private
  725.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_scanMultipart
  726.     */
  727.     function _scanMultipart(&$mid&$pid&$i$MIME$action 'add'$look_for 'all'$pid_add = 1$get_alternative = true)
  728.     {
  729.         // Find subparts, create variables
  730.         // Create inline parts first, and attachments second
  731.  
  732.         // Get all top level parts, with the exception of the part currently being viewed
  733.         // If top level part contains multipart/alternative go into that subpart to
  734.         // retrieve the other inline message part to display
  735.  
  736.         // If this part is message/rfc822 get subparts that begin with this part id
  737.         // Skip multipart/alternative message part
  738.         // Find the displayable message, get text/plain part if $getInline is true
  739.         if ($action == 'add'{
  740.  
  741.            $excludeMIME $MIME;
  742.            $MIME        ($excludeMIME == 'text/plain')'text/html' 'text/plain';
  743.            $in          = 0;
  744.            $a           = 0;
  745.  
  746.         else if ($action == 'get'{
  747.            $excludeMIME = null;
  748.         }
  749.  
  750.         $pid_len      strlen($pid);
  751.         $this_nesting count(explode('.'$pid));
  752.  
  753.         foreach ($this->structure[$mid]['pid'as $p => $id{
  754.  
  755.             // To look at the next level of nesting one needs to determine at which level
  756.             // of nesting the program currently resides, this needs to be independent of the
  757.             // part id length, since part ids can get into double digits (let's hope they
  758.             // don't get into triple digits!)
  759.  
  760.             // To accomplish this we'll explode the part id on the dot to get a count of the
  761.             // nesting, then compare the string with the next level in.
  762.  
  763.             $nesting count(explode('.'$this->structure[$mid]['pid'][$p]));
  764.  
  765.             switch ($look_for{
  766.                 case 'all':
  767.                 {
  768.                     $condition (($nesting == ($this_nesting + 1)) && $pid == substr($this->structure[$mid]['pid'][$p]0$pid_len));
  769.                     break;
  770.                 }
  771.                 case 'multipart':
  772.                 {
  773.                     $condition (($nesting == ($this_nesting + 1)) && ($pid == substr($this->structure[$mid]['pid'][$p]0)));
  774.                     break;
  775.                 }
  776.                 // Used if *all* parts are being retrieved
  777.                 case 'none':
  778.                 {
  779.                     $condition = true;
  780.                     break;
  781.                 }
  782.                 // To gaurantee a top-level part, detect whether a period appears in the pid string
  783.                 case 'top':
  784.                 default:
  785.                 {
  786.                     if ($this->_isMultipart($mid'related'|| $this->_isMultipart($mid'mixed')) {
  787.                         $condition (!stristr($this->structure[$mid]['pid'][$p]'.'|| ($nesting == 2&& substr($this->msg[$mid]['pid']01== substr($this->structure[$mid]['pid'][$p]01));
  788.                     else {
  789.                         $condition (!stristr($this->structure[$mid]['pid'][$p]'.'));
  790.                     }
  791.                 }
  792.             }
  793.  
  794.             if ($condition == true{
  795.                 if ($this->structure[$mid]['ftype'][$p== 'multipart/alternative' || $this->structure[$mid]['ftype'][$p== 'multipart/mixed'{
  796.                     foreach ($this->structure[$mid]['pid'as $mp => $mpid{
  797.                         // Part must begin with last matching part id and be two levels in
  798.                         $sub_nesting count(explode('.'$this->structure[$mid]['pid'][$p]));
  799.  
  800.                         if (( $this->structure[$mid]['ftype'][$mp== $MIME &&
  801.                               $get_alternative == true &&
  802.                               ($sub_nesting == ($this_nesting $pid_add)) &&
  803.                               ($pid == substr($this->structure[$mid]['pid'][$mp]0strlen($this->structure[$mid]['pid'][$p])))
  804.                            )) {
  805.  
  806.                             if ($action == 'add'{
  807.                                  $this->_addPart($in$mid$mp'in');
  808.                                  break;
  809.                             else if ($action == 'get' && !isset($this->structure[$mid]['fname'][$mp]&& empty($this->structure[$mid]['fname'][$mp])) {
  810.                                 return $this->structure[$mid]['pid'][$mp];
  811.                             }
  812.  
  813.                         else if ($this->structure[$mid]['ftype'][$mp== 'multipart/alternative' && $action == 'get'{
  814.  
  815.                             // Need to match this PID to next level in
  816.                             $pid          = (string) $this->structure[$mid]['pid'][$mp];
  817.                             $pid_len      strlen($pid);
  818.                             $this_nesting count(explode('.'$pid));
  819.                             $pid_add       = 2;
  820.                             continue;
  821.                         }
  822.                     }
  823.                 else if ($this->structure[$mid]['disposition'][$p== 'inline' && $this->structure[$mid]['ftype'][$p!= 'multipart/related' && $this->structure[$mid]['ftype'][$p!= 'multipart/mixed'{
  824.                     if (( $action == 'add' &&
  825.                           $this->structure[$mid]['ftype'][$p!= $excludeMIME &&
  826.                           $pid != $this->structure[$mid]['pid'][$p]
  827.                        || (
  828.                           $action == 'add' &&
  829.                           $this->structure[$mid]['ftype'][$p== $excludeMIME &&
  830.                           isset($this->structure[$mid]['fname'][$p]&&
  831.                           $pid != $this->structure[$mid]['pid'][$p]
  832.                        || (
  833.                           $action == 'add' && isset($this->structure[$mid]['fallback'][0])
  834.                        )) {
  835.  
  836.                         $this->_addPart($in$mid$p'in');
  837.  
  838.                     else if ($action == 'get' && $this->structure[$mid]['ftype'][$p== $MIME && !isset($this->structure[$mid]['fname'][$p])) {
  839.                         return $this->structure[$mid]['pid'][$p];
  840.                     }
  841.                 else if ($action == 'add' && $this->structure[$mid]['disposition'][$p== 'attachment'{
  842.                     $this->_addPart($a$mid$p'at');
  843.                 }
  844.             }
  845.         }
  846.  
  847.         return false;
  848.     }
  849.  
  850.     /**
  851.     * Determines whether a message contains a multipart/(insert subtype here) part.
  852.     * Only called on by $this->_scanMultipart
  853.     *
  854.     * @return   BOOL 
  855.     * @access   private
  856.     * @see      _scanMultipart
  857.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_isMultipart
  858.     */
  859.     function _isMultipart($mid$subtype)
  860.     {
  861.         $ret $this->extractMIME($midarray('multipart/'.$subtype));
  862.         return (!empty($ret&& is_array($ret&& count($ret>= 1)? true : false;
  863.     }
  864.  
  865.     /**
  866.     * Looks to see if this part has any inline parts associated with it.
  867.     * It looks up the message tree for parts with CID entries and
  868.     * indexes those entries, whereas an algorithm may be ran to replace
  869.     * inline CIDs with a part viewer.
  870.     *
  871.     * @param   int      &$mid          message id
  872.     * @param   string   &$pid          part id
  873.     * @param   array    $secureMIME    array of acceptable CID MIME types.
  874.     *
  875.     *  The $secureMIME argument allows you to limit the types of files allowed
  876.     *  in a multipart/related message, for instance, to prevent a browser from
  877.     *  automatically initiating download of a part that could contain potentially
  878.     *  malicious code.
  879.     *
  880.     *  Suggested MIME types:
  881.     *  text/plain, text/html, text/css, image/jpeg, image/pjpeg, image/gif
  882.     *  image/png,  image/x-png, application/xml, application/xhtml+xml,
  883.     *  text/xml
  884.     *
  885.     *  MIME types are not limited by default.
  886.     *
  887.     * @return  array|false
  888.     *     On success returns an array of parts associated with the current message,
  889.     *     including the cid of the part, the part id and the MIME type.
  890.     *
  891.     * @access  public
  892.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/getRelatedParts
  893.     */
  894.     function getRelatedParts(&$mid&$pid$secureMIME = array())
  895.     {
  896.         // Check to see if this part has already been parsed
  897.         $this->_checkIfParsed($mid);
  898.  
  899.         // Message has a PID of 1.1.2
  900.         // Cid parts are located at the prior level of nesting at 1.x
  901.         // From the supplied PID, go back one level of nesting.
  902.         // Compare the first number of the supplied PID against the current PID.
  903.         // Look for a cid entry in the structure array.
  904.         // Index the PID and CID of the part.
  905.         //
  906.         // Supplied pid must correspond to a text/html part.
  907.         if (!empty($secureMIME&& is_array($secureMIME)) {
  908.             $this->error->push(Mail_IMAPv2_ERROR_ARGUMENT_REQUIRES_ARRAY'error'array('arg' => '$secureMIME''actual_value' => $secureMIME));
  909.             return false;
  910.         }
  911.  
  912.         $related = array();
  913.  
  914.         if (isset($this->structure[$mid]['pid']&& is_array($this->structure[$mid]['pid'])) {
  915.             if (strlen($pid> 1{
  916.                 $nesting count(explode('.'$pid));
  917.                 $compare substr($pid0-4);
  918.                 foreach ($this->structure[$mid]['pid'as $i => $rpid{
  919.                     // This level of nesting is one above the message part
  920.                     // The beginning of the pid string of the related part matches that of the
  921.                     // beginning of the pid supplied
  922.                     if (count(explode('.'$rpid)) == ($nesting - 1&& substr($rpid0-2== $compare{
  923.                         $this->_getCIDs($mid$i$secureMIME$related);
  924.                     }
  925.                 }
  926.             else if (strlen($pid== 1{
  927.                 // If the pid is in the first level of nesting, odds are the related parts are in the
  928.                 // sub level of nesting.
  929.                 foreach ($this->structure[$mid]['pid'as $i => $rpid{
  930.                     // The part is one level under and the first number matches that
  931.                     // of its parent part.
  932.                     if (count(explode('.'$rpid)) == 2 && substr($rpid01== $pid{
  933.                         $this->_getCIDs($mid$i$secureMIME$related);
  934.                     }
  935.                 }
  936.             }
  937.         else {
  938.             $this->error->push(Mail_IMAPv2_ERROR'error'null'Message structure does not exist.');
  939.         }
  940.         return (count($related>= 1)$related : false;
  941.     }
  942.  
  943.     /**
  944.     * Helper function for getRelatedParts
  945.     *
  946.     * @return void 
  947.     * @access private
  948.     * @see    getRelatedParts
  949.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_getCIDs
  950.     */
  951.     function _getCIDs(&$mid&$i&$secureMIME&$related)
  952.     {
  953.         if ((isset($this->structure[$mid]['cid'][$i])) && (empty($secureMIME|| is_array($secureMIME&& in_array($this->structure[$mid]['ftype'][$i]$secureMIME))) {
  954.             $related['cid'][$this->structure[$mid]['cid'][$i];
  955.             $related['pid'][$this->structure[$mid]['pid'][$i];
  956.             $related['ftype'][$this->structure[$mid]['ftype'][$i];
  957.         }
  958.     }
  959.  
  960.     /**
  961.     * Destroys variables set by {@link getParts} and _declareParts.
  962.     *
  963.     * @param    integer  &$mid   message id
  964.     * @return   void 
  965.     * @access   public
  966.     * @see      getParts
  967.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/unsetParts
  968.     */
  969.     function unsetParts(&$mid)
  970.     {
  971.         unset($this->msg[$mid]);
  972.         unset($this->structure[$mid]);
  973.         return;
  974.     }
  975.  
  976.     /**
  977.     * Adds information to the member variable inline part 'in' and attachment 'at' arrays.
  978.     *
  979.     * @param    int     &$n   offset part counter
  980.     * @param    int     &$mid  message id
  981.     * @param    int     &$i    offset structure reference counter
  982.     * @return   void 
  983.     * @access   private
  984.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_addPart
  985.     */
  986.     function _addPart(&$n&$mid&$i$part)
  987.     {
  988.         foreach ($this->fields as $field{
  989.             if (isset($this->structure[$mid][$field][$i]&& !empty($this->structure[$mid][$field][$i])) {
  990.                 $this->msg[$mid][$part][$field][$n$this->structure[$mid][$field][$i];
  991.             }
  992.         }
  993.         $n++;
  994.         return;
  995.     }
  996.  
  997.     /**
  998.     * Returns entire unparsed message body.  See {@link imap_body} for options.
  999.     *
  1000.     * @param    int     &$mid      message id
  1001.     * @return   string|null
  1002.     * @tutorial http://www.smilingsouls.net/index.php?content=Mail_IMAPv2/getRawMessage
  1003.     * @access   public
  1004.     * @see      imap_body
  1005.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/getRawMessage
  1006.     */
  1007.     function getRawMessage(&$mid)
  1008.     {
  1009.         $opt (isset($this->option['body']))$this->option['body': null;
  1010.         return imap_body($this->mailbox$mid$opt);
  1011.     }
  1012.  
  1013.     /**
  1014.     * Searches parts array set in $this->_declareParts() for a displayable message.
  1015.     * If the part id passed is message/rfc822 looks in subparts for a displayable body.
  1016.     * Attempts to return a text/html inline message part by default. And will
  1017.     * automatically attempt to find a text/plain part if a text/html part could
  1018.     * not be found.
  1019.     *
  1020.     * Returns an array containing three associative indices; 'ftype', 'fname' and
  1021.     * 'message'.  'ftype' contains the MIME type of the message, 'fname', the original
  1022.     * file name, if any, empty string otherwise.  And 'message', which contains the
  1023.     * message body itself which is returned decoded from base64 or quoted-printable if
  1024.     * either of those encoding types are specified, returns untouched otherwise.
  1025.     * Returns false on failure.
  1026.     *
  1027.     * @param    int     &$mid                    message id
  1028.     * @param    string  $pid                     part id
  1029.     * @param    int     $action 
  1030.     *       (optional) options for body return.  Set to one of the following:
  1031.     *       Mail_IMAPv2_BODY (default), if part is message/rfc822 searches subparts for a
  1032.     *       displayable body and returns the body decoded as part of an array.
  1033.     *       Mail_IMAPv2_LITERAL, return the message for the specified $pid without searching
  1034.     *       subparts or decoding the message (may return unparsed message) body is returned
  1035.     *       undecoded as a string.
  1036.     *       Mail_IMAPv2_LITERAL_DECODE, same as Mail_IMAPv2_LITERAL, except message decoding is
  1037.     *       attempted from base64 or quoted-printable encoding, returns undecoded string
  1038.     *       if decoding failed.
  1039.     *
  1040.     * @param    string  $getPart 
  1041.     *       (optional) one of text/plain or text/html, allows the specification of the default
  1042.     *       part to return from multipart messages, text/html by default.
  1043.     *
  1044.     * @param    int     $attempt 
  1045.     *       (optional) used internally by getBody to track attempts at finding the
  1046.     *       right part to display for the body of the message.
  1047.     *
  1048.     * @return   array|string|false
  1049.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/getBody
  1050.     * @access   public
  1051.     * @see      imap_fetchbody
  1052.     * @see      $this->getParts
  1053.     * @since    PHP 4.2.0
  1054.     */
  1055.     function getBody(&$mid$pid '1'$action = 0$get_mime 'text/html'$attempt = 1)
  1056.     {
  1057.         $options (isset($this->option['fetchbody']))$this->option['fetchbody': null;
  1058.  
  1059.         if ($action == Mail_IMAPv2_LITERAL{
  1060.             return @imap_fetchbody($this->mailbox$mid$pid$options);
  1061.         }
  1062.  
  1063.         $this->_checkIfParsed($midtrue$get_mime);
  1064.  
  1065.         if (false !== ($i array_search((string) $pid$this->structure[$mid]['pid']))) {
  1066.             if ($action == Mail_IMAPv2_LITERAL_DECODE{
  1067.                 $msg_body @imap_fetchbody($this->mailbox$mid$pid$options);
  1068.                 return $this->_decodeMessage($msg_body$this->structure[$mid]['encoding'][$i]);
  1069.             }
  1070.  
  1071.             // If this is an attachment, and the part is message/rfc822 update the pid to the subpart
  1072.             // If this is an attachment, and the part is multipart/alternative update the pid to the subpart
  1073.             if ($this->structure[$mid]['ftype'][$i== 'message/rfc822' || $this->structure[$mid]['ftype'][$i== 'multipart/related' || $this->structure[$mid]['ftype'][$i== 'multipart/alternative'{
  1074.  
  1075.                 $new_pid ($this->structure[$mid]['ftype'][$i== 'message/rfc822' || $this->structure[$mid]['ftype'][$i== 'multipart/related')$this->_scanMultipart($mid$pid$i$get_mime'get''all'1$this->_scanMultipart($mid$pid$i$get_mime'get''multipart'1);
  1076.  
  1077.                 // if a new pid for text/html couldn't be found, try again, this time look for text/plain
  1078.                 switch(true{
  1079.                     case (!empty($new_pid)):                             $pid $new_pid; break;
  1080.                     case (empty($new_pid&& $get_mime == 'text/html'):   return ($attempt == 1)$this->getBody($mid$pid$action'text/plain'2: false;
  1081.                     case (empty($new_pid&& $get_mime == 'text/plain'):  return ($attempt == 1)$this->getBody($mid$pid$action'text/html'2: false;
  1082.                 }
  1083.             }
  1084.  
  1085.             // Update the key for the new pid
  1086.             if (!empty($new_pid)) {
  1087.                 if (false === ($i array_search((string) $pid$this->structure[$mid]['pid']))) {
  1088.                     // Something's afoot!
  1089.                     $this->error->push(Mail_IMAPv2_ERROR'error'array('mid' => $mid'pid' => $pid)'Unable to find a suitable replacement part ID. Message: may be poorly formed, corrupted, or not supported by the Mail_IMAPv2 parser.');
  1090.                     return false;
  1091.                 }
  1092.             }
  1093.  
  1094.             $msg_body = imap_fetchbody($this->mailbox$mid$pid$options);
  1095.  
  1096.             if ($msg_body == null{
  1097.                 $this->error->push(Mail_IMAPv2_ERROR'error'array('mid' => $mid'pid' => $pid)'Message body is null.');
  1098.                 return false;
  1099.             }
  1100.  
  1101.             // Decode message.
  1102.             // Because the body returned may not correspond with the original PID, return
  1103.             // an array which also contains the MIME type and original file name, if any.
  1104.             $body['message'$this->_decodeMessage($msg_body$this->structure[$mid]['encoding'][$i]$this->structure[$mid]['charset'][$i]);
  1105.             $body['ftype']   $this->structure[$mid]['ftype'][$i];
  1106.             $body['fname']   (isset($this->structure[$mid]['fname'][$i]))$this->structure[$mid]['fname'][$i'';
  1107.             $body['charset'$this->structure[$mid]['charset'][$i];
  1108.  
  1109.             return $body;
  1110.         else {
  1111.             $this->error->push(Mail_IMAPv2_ERROR_INVALID_PID'error'array('pid' => $pid));
  1112.             return false;
  1113.         }
  1114.  
  1115.         return false;
  1116.     }
  1117.  
  1118.     /**
  1119.     * Decode a string from quoted-printable or base64 encoding.  If
  1120.     * neither of those encoding types are specified, returns string
  1121.     * untouched.
  1122.     *
  1123.     * @param    string  &$body           string to decode
  1124.     * @param    string  &$encoding       encoding to decode from.
  1125.     * @return   string 
  1126.     * @access   private
  1127.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_decodeMessage
  1128.     */
  1129.     function _decodeMessage(&$body&$encoding&$charset)
  1130.     {
  1131.         switch ($encoding{
  1132.             case 'quoted-printable':
  1133.                 return ($charset == 'utf-8')utf8_decode(imap_utf8(imap_qprint($body))) : imap_qprint($body);
  1134.             case 'base64':            return imap_base64($body);
  1135.             default:                  return $body;
  1136.         }
  1137.     }
  1138.  
  1139.     /**
  1140.     * Searches structure defined in $this->_declareParts for the top-level default message.
  1141.     * Attempts to find a text/html default part, if no text/html part is found,
  1142.     * automatically attempts to find a text/plain part. Returns the part id for the default
  1143.     * top level message part on success. Returns false on failure.
  1144.     *
  1145.     * @param    int     &$mid           message id
  1146.     * @param    string  $getPart 
  1147.     *      (optional) default MIME type to look for, one of text/html or text/plain
  1148.     *      text/html by default.
  1149.     * @param    int     $attempt 
  1150.     *      (optional) Used internally by _getDefaultPid to track the method's attempt
  1151.     *      at retrieving the correct default part to display.
  1152.     *
  1153.     * @return   string 
  1154.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_getDefaultPid
  1155.     * @access   private
  1156.     */
  1157.     function _getDefaultPid(&$mid$get_mime 'text/html'$attempt = 1)
  1158.     {
  1159.         // Check to see if this part has already been parsed
  1160.         $this->_checkIfParsed($midfalse);
  1161.  
  1162.         // Look for a text/html message part
  1163.         // If no text/html message part was found look for a text/plain message part
  1164.         $part ($get_mime == 'text/html')? array('text/html''text/plain': array('text/plain''text/html');
  1165.  
  1166.         foreach ($part as $mime{
  1167.             if (0 !== count($msg_part @array_keys($this->structure[$mid]['ftype']$mime))) {
  1168.                 foreach ($msg_part as $i{
  1169.                     if ($this->structure[$mid]['disposition'][$i== 'inline' && !stristr($this->structure[$mid]['pid'][$i]'.')) {
  1170.                         $this->msg[$mid]['pid'$this->structure[$mid]['pid'][$i];
  1171.                         return $this->structure[$mid]['pid'][$i];
  1172.                     }
  1173.                 }
  1174.             }
  1175.         }
  1176.  
  1177.         // If no text/plain or text/html part was found
  1178.         // Look for a multipart/alternative part
  1179.         $mp_nesting = 1;
  1180.         $pid_len    = 1;
  1181.  
  1182.         foreach ($this->structure[$mid]['pid'as $p => $id{
  1183.             $nesting count(explode('.'$this->structure[$mid]['pid'][$p]));
  1184.  
  1185.             if (!isset($mpid)) {
  1186.                 if ($nesting == 1 && isset($this->structure[$mid]['ftype'][$p]&& ($this->structure[$mid]['ftype'][$p== 'multipart/related')) {
  1187.                     $mp_nesting = 2;
  1188.                     $pid_len    = 3;
  1189.                     continue;
  1190.                 }
  1191.                 if ($nesting == $mp_nesting && isset($this->structure[$mid]['ftype'][$p]&& ($this->structure[$mid]['ftype'][$p== 'multipart/alternative'  || $this->structure[$mid]['ftype'][$p]  == 'multipart/mixed')) {
  1192.                     $mpid $this->structure[$mid]['pid'][$p];
  1193.                     continue;
  1194.                 }
  1195.             }
  1196.  
  1197.             if (isset($mpid&& $nesting == ($mp_nesting + 1&& $this->structure[$mid]['ftype'][$p== $get_mime && $mpid == substr($this->structure[$mid]['pid'][$p]0$pid_len)) {                
  1198.                 $this->msg[$mid]['pid'$this->structure[$mid]['pid'][$p];
  1199.                 return $this->structure[$mid]['pid'][$p];
  1200.             }
  1201.         }
  1202.  
  1203.         // if a text/html part was not found, call on the function again
  1204.         // and look for text/plain
  1205.         // if the application was unable to find a text/plain part
  1206.         switch ($get_mime{
  1207.             case 'text/html':  $rtn ($attempt == 1)$this->_getDefaultPid($mid'text/plain'2: false;    break;
  1208.             case 'text/plain'$rtn ($attempt == 1)$this->_getDefaultPid($mid'text/html'2)  : false;    break;
  1209.             default:           $rtn = false;
  1210.         }
  1211.  
  1212.         if ($rtn == false && $attempt == 2{
  1213.             if (isset($this->structure[$mid]['ftype'][0])) {
  1214.                 $this->structure[$mid]['fallback'][0= true;
  1215.             else {
  1216.                 $this->error->push(Mail_IMAPv2_ERROR'error'null'Message contains no MIME types.');
  1217.             }
  1218.         }
  1219.  
  1220.         $this->msg[$mid]['pid'($rtn == false)? 1 : $rtn;
  1221.  
  1222.         return $this->msg[$mid]['pid'];
  1223.     }
  1224.  
  1225.     /**
  1226.     * Searches all message parts for the specified MIME type.  Use {@link getBody}
  1227.     * with $action option Mail_IMAPv2_LITERAL_DECODE to view MIME type parts retrieved.
  1228.     * If you need to access the MIME type with filename use normal {@link getBody}
  1229.     * with no action specified.
  1230.     *
  1231.     * Returns an array of part ids on success.
  1232.     * Returns false if MIME couldn't be found, or on failure.
  1233.     *
  1234.     * @param    int           &$mid           message id
  1235.     * @param    string|array $MIMEs          mime type to extract
  1236.     * @return   array|false
  1237.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/extractMIME
  1238.     * @access   public
  1239.     */
  1240.     function extractMIME(&$mid$MIMEs)
  1241.     {
  1242.         $this->_checkIfParsed($mid);
  1243.  
  1244.         if (is_array($this->structure[$mid]['ftype'])) {
  1245.             if (is_array($MIMEs)) {
  1246.                 foreach ($MIMEs as $MIME{
  1247.                     if (0 !== count($keys array_keys($this->structure[$mid]['ftype']$MIME))) {
  1248.                         foreach ($keys as $key{
  1249.                             $rtn[$this->structure[$mid]['pid'][$key];
  1250.                         }
  1251.                     }
  1252.                 }
  1253.             else {
  1254.                 $this->error->push(Mail_IMAPv2_ERROR_ARGUMENT_REQUIRES_ARRAY'error'array('arg' => '$MIMEs''actual_value' => $MIMEs));
  1255.             }
  1256.         else {
  1257.             $this->error->push(Mail_IMAPv2_ERROR'error'null'Member variable $this->structure[\'ftype\'] is not an array');
  1258.         }
  1259.  
  1260.         return (isset($rtn))$rtn : false;
  1261.     }
  1262.  
  1263.     /**
  1264.     * Set member variable {@link $rawHeaders} to contain Raw Header information
  1265.     * for a part.  Returns default header part id on success, returns false on failure.
  1266.     *
  1267.     * @param    int     &$mid          message_id
  1268.     * @param    string  $pid           (optional) part id to retrieve headers for
  1269.     * @param    bool    $rtn 
  1270.     *    Decides what to return. One of true|false|return_pid
  1271.     *    If true return the raw headers (returns the headers by default)
  1272.     *
  1273.     * @return   string|false
  1274.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/getRawHeaders
  1275.     * @access   public
  1276.     * @see      imap_fetchbody
  1277.     * @see      getHeaders
  1278.     */
  1279.     function getRawHeaders(&$mid$pid '0'$rtn = true$pid_check = false)
  1280.     {
  1281.         $this->_checkIfParsed($mid);
  1282.  
  1283.         if ($pid == $this->msg[$mid]['pid']{
  1284.             $pid '0';
  1285.         }
  1286.  
  1287.         if ($pid != '0'{
  1288.             if (false === ($pid $this->_defaultHeaderPid($mid$pid))) {
  1289.                 $this->error->push(Mail_IMAPv2_ERROR_INVALID_PID'error'array('pid' => $pid));
  1290.                 return false;
  1291.             }
  1292.         }
  1293.  
  1294.         if ($pid == '0' && $pid_check == true{
  1295.             return true;
  1296.         else if ($pid_check == true{
  1297.             // This variable was $ret, I suspect it was an error
  1298.             // Change might have adverse effects though.
  1299.             // $ret = true;
  1300.         }
  1301.  
  1302.         if ($pid == '0'{
  1303.             $opt (isset($this->option['fetchheader']))$this->option['fetchheader': null;
  1304.             $raw_headers @imap_fetchheader($this->mailbox$mid$opt);
  1305.         else {
  1306.             $opt (isset($this->option['fetchbody']))$this->option['fetchbody': null;
  1307.             $raw_headers @imap_fetchbody($this->mailbox$mid$pid$opt);
  1308.         }
  1309.  
  1310.         if ($rtn == true{
  1311.             return $raw_headers;
  1312.         else {
  1313.             $this->header[$mid]['raw'$raw_headers;
  1314.             return true;
  1315.         }
  1316.     }
  1317.  
  1318.     /**
  1319.     * Set member variable containing header information.  Creates an array containing
  1320.     * associative indices referring to various header information.  Use {@link var_dump}
  1321.     * or {@link print_r} on the {@link $header} member variable to view information
  1322.     * gathered by this function.
  1323.     *
  1324.     * If $ret is true, returns array containing header information on success and false
  1325.     * on failure.
  1326.     *
  1327.     * If $ret is false, adds the header information to the $header member variable
  1328.     * and returns BOOL.
  1329.     *
  1330.     * @param    int     &$mid           message id
  1331.     * @param    string  &$pid           (optional) part id to retrieve headers for.
  1332.     * @param    bool    $rtn 
  1333.     *    (optional) If true return the headers, if false, assign to $header member variable.
  1334.     *
  1335.     * @param    array   $args 
  1336.     *    (optional) Associative array containing extra arguments.
  1337.     *
  1338.     *        $args['from_length'] int
  1339.     *            From field length for imap_headerinfo.
  1340.     *
  1341.     *        $args['subject_length'] int
  1342.     *            Subject field length for imap_headerinfo
  1343.     *
  1344.     *        $args['default_host'] string
  1345.     *            Default host for imap_headerinfo & imap_rfc822_parse_headers
  1346.     *
  1347.     * @return   Array|BOOL
  1348.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/getHeaders
  1349.     * @access   public
  1350.     * @see      getParts
  1351.     * @see      imap_fetchheader
  1352.     * @see      imap_fetchbody
  1353.     * @see      imap_headerinfo
  1354.     * @see      imap_rfc822_parse_headers
  1355.     */
  1356.     function getHeaders(&$mid$pid '0'$rtn = false$args = array())
  1357.     {
  1358.         $this->_checkIfParsed($mid);
  1359.  
  1360.         if ($pid == $this->msg[$mid]['pid']{
  1361.             $pid '0';
  1362.         }
  1363.  
  1364.         if ($pid !== '0'{
  1365.             if (false === ($raw_headers $this->getRawHeaders($mid$pidtruetrue))) {
  1366.                 return false;
  1367.             }
  1368.  
  1369.             if ($raw_headers == true{
  1370.                 $pid '0';
  1371.             }
  1372.         }
  1373.  
  1374.         if (!isset($args['from_length'])) {
  1375.             $args['from_length'= 1024;
  1376.         }
  1377.  
  1378.         if (!isset($args['subject_length'])) {
  1379.             $args['subject_length'= 1024;
  1380.         }
  1381.  
  1382.         if (!isset($args['default_host'])) {
  1383.             $args['default_host'= null;
  1384.         }
  1385.  
  1386.         // Parse the headers
  1387.         $header_info ($pid === '0')?
  1388.                 imap_headerinfo($this->mailbox$mid$args['from_length']$args['subject_length']$args['default_host'])
  1389.             :
  1390.                 imap_rfc822_parse_headers($raw_headers$args['default_host']);
  1391.  
  1392.         // Since individual member variable creation might create extra overhead,
  1393.         // and having individual variables referencing this data and the original
  1394.         // object would be too much as well, we'll just copy the object into an
  1395.         // associative array, preform clean-up on those elements that require it,
  1396.         // and destroy the original object after copying.
  1397.  
  1398.         if (!is_object($header_info)) {
  1399.             $this->error->push(Mail_IMAPv2_ERROR_INVALID_PID'error'array('pid' => $pid));
  1400.             return false;
  1401.         }
  1402.  
  1403.         $headers get_object_vars($header_info);
  1404.  
  1405.         foreach ($headers as $key => $value{
  1406.             if (!is_object($value&& !is_array($value)) {
  1407.                 // Decode all the headers using utf8_decode(imap_utf8())
  1408.                 $this->header[$mid][$keyutf8_decode(imap_utf8($value));
  1409.             }
  1410.         }
  1411.  
  1412.         // copy udate or create it from date string.
  1413.         $this->header[$mid]['udate'(isset($header_info->udate&& !empty($header_info->udate))$header_info->udate : strtotime($header_info->Date);
  1414.  
  1415.         // clean up addresses
  1416.         $line['from';
  1417.         $line['reply_to';
  1418.         $line['sender';
  1419.         $line['return_path';
  1420.         $line['to';
  1421.         $line['cc';
  1422.         $line['bcc';
  1423.  
  1424.         for ($i = 0; $i count($line)$i++{
  1425.             if (isset($header_info->$line[$i])) {
  1426.                 $this->_parseHeaderLine($mid$header_info->$line[$i]$line[$i]);
  1427.             }
  1428.         }
  1429.  
  1430.         // All possible information has been copied, destroy original object
  1431.         unset($header_info);
  1432.  
  1433.         if ($rtn = true{
  1434.             return $this->header[$mid];
  1435.         else {
  1436.             return false;
  1437.         }
  1438.     }
  1439.  
  1440.     /**
  1441.     * Parse header information from the given line and add it to the {@link $header}
  1442.     * array.  This function is only used by {@link getRawHeaders}.
  1443.     *
  1444.     * @param     string   &$line 
  1445.     * @param     string   $name 
  1446.     * @return    array 
  1447.     * @access    private
  1448.     * @tutorial  http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_parseHeaderLine
  1449.     */
  1450.     function _parseHeaderLine(&$mid&$line$name{
  1451.         if (isset($line&& count($line>= 1{
  1452.             $i = 0;
  1453.             foreach ($line as $object{
  1454.                 if (isset($object->adl)) {
  1455.                     $this->header[$mid][$name.'_adl'][$i$object->adl;
  1456.                 }
  1457.                 if (isset($object->mailbox)) {
  1458.                     $this->header[$mid][$name.'_mailbox'][$i$object->mailbox;
  1459.                 }
  1460.                 if (isset($object->personal)) {
  1461.                     $this->header[$mid][$name.'_personal'][$i$object->personal;
  1462.                 }
  1463.                 if (isset($object->host)) {
  1464.                     $this->header[$mid][$name.'_host'][$i$object->host;
  1465.                 }
  1466.                 if (isset($object->mailbox&& isset($object->host)) {
  1467.                     $this->header[$mid][$name][$i$object->mailbox.'@'.$object->host;
  1468.                 }
  1469.                 $i++;
  1470.             }
  1471.             // Return the full lines "toaddress", "fromaddress", "ccaddress"... etc
  1472.             if (isset(${$name."address"})) {
  1473.                 $this->header[$mid][$name.'address'][$i= ${$name."address"};
  1474.             }
  1475.         }
  1476.     }
  1477.  
  1478.     /**
  1479.     * Finds and returns a default part id for headers and matches any sub message part to
  1480.     * the appropriate headers.  Returns false on failure and may return a value that
  1481.     * evaluates to false, use the '===' operator for testing this function's return value.
  1482.     *
  1483.     * @param    int     &$mid            message id
  1484.     * @param    string  $pid             part id
  1485.     * @return   string|false
  1486.     * @access   private
  1487.     * @see      getHeaders
  1488.     * @see      getRawHeaders
  1489.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/_defaultHeaderPid
  1490.     */
  1491.     function _defaultHeaderPid(&$mid$pid)
  1492.     {
  1493.         // pid is modified in this function, so don't pass by reference (will create a logic error)
  1494.         $this->_checkIfParsed($mid);
  1495.  
  1496.         // retrieve key for this part, so that the information may be accessed
  1497.         if (false !== ($i array_search((string) $pid$this->structure[$mid]['pid']))) {
  1498.  
  1499.             // If this part is message/rfc822 display headers for this part
  1500.             if ($this->structure[$mid]['ftype'][$i== 'message/rfc822'{
  1501.  
  1502.                 $rtn = (string) $pid.'.0';
  1503.  
  1504.             else if ($pid == $this->msg[$mid]['pid']{
  1505.  
  1506.                 $rtn = (string) '0';
  1507.  
  1508.             else {
  1509.  
  1510.                 $pid_len strlen($pid);
  1511.                 $this_nesting count(explode('.'$pid));
  1512.  
  1513.                 // Deeper searching may be required, go back to this part's parent.
  1514.                 if (!stristr($pid'.'|| ($this_nesting - 1== 1{
  1515.                     $rtn = (string) '0';
  1516.                 else if ($this_nesting > 2{
  1517.                     // Look at previous parts until a message/rfc822 part is found.
  1518.                     for ($pos $this_nesting - 1; $pos > 0; $pos -= 1{
  1519.  
  1520.                         foreach ($this->structure[$mid]['pid'as $p => $aid{
  1521.  
  1522.                             $nesting count(explode('.'$this->structure[$mid]['pid'][$p]));
  1523.  
  1524.                             if ($nesting == $pos && ($this->structure[$mid]['ftype'][$p== 'message/rfc822' || $this->structure[$mid]['ftype'][$p== 'multipart/related')) {
  1525.                                 // Break iteration and return!
  1526.                                 return (string) $this->structure[$mid]['pid'][$p].'.0';
  1527.                             }
  1528.                         }
  1529.                     }
  1530.  
  1531.                     $rtn ($pid_len == 3)? (string) '0' : false;
  1532.  
  1533.                 else {
  1534.                     $rtn = false;
  1535.                 }
  1536.             }
  1537.             return $rtn;
  1538.         else {
  1539.             // Something's afoot!
  1540.             $this->error->push(Mail_IMAPv2_ERROR_INVALID_PID'error'array('pid' => $pid));
  1541.             return false;
  1542.         }
  1543.     }
  1544.  
  1545.     /**
  1546.     * Destroys variables set by {@link getHeaders}.
  1547.     *
  1548.     * @param    int     &$mid            message id
  1549.     * @return   void 
  1550.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/unsetHeaders
  1551.     * @access   public
  1552.     * @see      getHeaders
  1553.     */
  1554.     function unsetHeaders(&$mid)
  1555.     {
  1556.         unset($this->header[$mid]);
  1557.         return;
  1558.     }
  1559.  
  1560.     /**
  1561.     * Converts an integer containing the number of bytes in a file to one of Bytes, Kilobytes,
  1562.     * Megabytes, or Gigabytes, appending the unit of measurement.
  1563.     *
  1564.     * This method may be called statically.
  1565.     *
  1566.     * @param    int     $bytes 
  1567.     * @return   string 
  1568.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/convertBytes
  1569.     * @access   public
  1570.     * @static
  1571.     */
  1572.     function convertBytes($bytes)
  1573.     {
  1574.         switch (true{
  1575.             case ($bytes pow(2,10)):                             return $bytes.' Bytes';
  1576.             case ($bytes >= pow(2,10&& $bytes pow(2,20)):      return round($bytes pow(2,10)0).' KB';
  1577.             case ($bytes >= pow(2,20&& $bytes pow(2,30)):      return round($bytes pow(2,20)1).' MB';
  1578.             case ($bytes pow(2,30)):                             return round($bytes pow(2,30)2).' GB';
  1579.         }
  1580.     }
  1581.  
  1582.     /**
  1583.     * Wrapper function for {@link imap_delete}.  Sets the marked for deletion flag.  Note: POP3
  1584.     * mailboxes do not remember flag settings between connections, for POP3 mailboxes
  1585.     * this function should be used in addtion to {@link expunge}.
  1586.     *
  1587.     * @param    int     &$mid   message id
  1588.     * @return   BOOL 
  1589.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/delete
  1590.     * @access   public
  1591.     * @see      imap_delete
  1592.     * @see      expunge
  1593.     */
  1594.     function delete(&$mid$separator "<br />\n")
  1595.     {
  1596.         if (!is_array($mid)) {
  1597.             if (!@imap_delete($this->mailbox$mid)) {
  1598.                 $this->error->push(Mail_IMAPv2_ERROR'error'array('mid' => $mid)'Unable to mark message for deletion.');
  1599.                 $rtn = false;
  1600.             else {
  1601.                 $rtn = true;
  1602.             }
  1603.         else {
  1604.             foreach ($mid as $id{
  1605.                 if (!@imap_delete($this->mailbox$id)) {
  1606.                     $this->error->push(Mail_IMAPv2_ERROR'error'array('mid' => $id)'Unable to mark message for deletion.');
  1607.                     $rtn = false;
  1608.                 }
  1609.             }
  1610.             $rtn = true;
  1611.         }
  1612.  
  1613.         return $rtn;
  1614.     }
  1615.  
  1616.     /**
  1617.     * Wrapper function for {@link imap_expunge}.  Expunges messages marked for deletion.
  1618.     *
  1619.     * @return   BOOL 
  1620.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/expunge
  1621.     * @access   public
  1622.     * @see      imap_expunge
  1623.     * @see      delete
  1624.     */
  1625.     function expunge()
  1626.     {
  1627.         if (imap_expunge($this->mailbox)) {
  1628.             return true;
  1629.         else {
  1630.             $this->error->push(Mail_IMAPv2_ERROR'error'null'Unable to expunge mailbox.');
  1631.             return false;
  1632.         }
  1633.     }
  1634.  
  1635.     /**
  1636.     * Wrapper function for {@link imap_errors}.  Implodes the array returned by imap_errors,
  1637.     * (if any) and returns the error text.
  1638.     *
  1639.     * @param    bool      $handler 
  1640.     *    How to handle the imap error stack, true by default. If true adds the errors
  1641.     *    to the PEAR_ErrorStack object. If false, returns the imap error stack.
  1642.     *
  1643.     * @param    string    $seperator 
  1644.     *    (optional) Characters to seperate each error message. "<br />\n" by default.
  1645.     *
  1646.     * @return   bool|string
  1647.     * @access   public
  1648.     * @see      imap_errors
  1649.     * @see      alerts
  1650.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/errors
  1651.     */
  1652.     function errors($handler = true$seperator "<br />\n")
  1653.     {
  1654.         $errors = imap_errors();
  1655.  
  1656.         if (empty($errors)) {
  1657.             return false;
  1658.         }
  1659.  
  1660.         if ($handler{
  1661.             foreach ($errors as $error{
  1662.                 $this->error->push(Mail_IMAPv2_ERROR'error'null$error);
  1663.             }
  1664.             return true;
  1665.         }
  1666.         return implode($seperator$errors);
  1667.     }
  1668.  
  1669.     /**
  1670.     * Wrapper function for {@link imap_alerts}.  Implodes the array returned by imap_alerts,
  1671.     * (if any) and returns the text.
  1672.     *
  1673.     * @param    bool      $handler 
  1674.     *    How to handle the imap error stack, true by default. If true adds the alerts
  1675.     *    to the PEAR_ErrorStack object. If false, returns the imap alert stack.
  1676.     *
  1677.     * @param    string    $seperator     Characters to seperate each alert message. '<br />\n' by default.
  1678.     * @return   bool|string
  1679.     * @access   public
  1680.     * @see      imap_alerts
  1681.     * @see      errors
  1682.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/alerts
  1683.     */
  1684.     function alerts($handler = true$seperator "<br />\n")
  1685.     {
  1686.         $alerts = imap_alerts();
  1687.  
  1688.         if (empty($alerts)) {
  1689.             return false;
  1690.         }
  1691.  
  1692.         if ($handler{
  1693.             foreach ($alerts as $alert{
  1694.                 $this->error->push(Mail_IMAPv2_ERROR'notice'null$alert);
  1695.             }
  1696.             return true;
  1697.         }
  1698.         return implode($seperator$alerts);
  1699.     }
  1700.  
  1701.     /**
  1702.     * Retreives information about the current mailbox's quota.  Rounds up quota sizes and
  1703.     * appends the unit of measurment.  Returns information in a multi-dimensional associative
  1704.     * array.
  1705.     *
  1706.     * @param    string   $folder    Folder to retrieve quota for.
  1707.     * @param    BOOL     $rtn 
  1708.     *    (optional) true by default, if true return the quota if false merge quota
  1709.     *    information into the $mailboxInfo member variable.
  1710.     * @return   array|false
  1711.     * @access   public
  1712.     * @see      imap_get_quotaroot
  1713.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/getQuota
  1714.     */
  1715.     function getQuota($folder = null$rtn = true)
  1716.     {
  1717.         if (empty($folder&& !isset($this->mailboxInfo['folder'])) {
  1718.             $folder 'INBOX';
  1719.         else if (empty($folder&& isset($this->mailboxInfo['folder'])) {
  1720.             $folder $this->mailboxInfo['folder'];
  1721.         }
  1722.  
  1723.         $q @imap_get_quotaroot($this->mailbox$folder);
  1724.  
  1725.         // STORAGE Values are returned in KB
  1726.         // Convert back to bytes first
  1727.         // Then round these to the simpliest unit of measurement
  1728.         if (isset($q['STORAGE']['usage']&& isset($q['STORAGE']['limit'])) {
  1729.             $q['STORAGE']['usage'$this->convertBytes($q['STORAGE']['usage'* 1024);
  1730.             $q['STORAGE']['limit'$this->convertBytes($q['STORAGE']['limit'* 1024);
  1731.         }
  1732.         if (isset($q['MESSAGE']['usage']&& isset($q['MESSAGE']['limit'])) {
  1733.             $q['MESSAGE']['usage'$this->convertBytes($q['MESSAGE']['usage']);
  1734.             $q['MESSAGE']['limit'$this->convertBytes($q['MESSAGE']['limit']);
  1735.         }
  1736.  
  1737.         if (empty($q['STORAGE']['usage']&& empty($q['STORAGE']['limit'])) {
  1738.            $this->error->push(Mail_IMAPv2_ERROR'error'null'Quota not available for this server.');
  1739.            return false;
  1740.         else if ($rtn{
  1741.             return $q;
  1742.         else {
  1743.             $this->mailboxInfo = array_merge($this->mailboxInfo$q);
  1744.             return true;
  1745.         }
  1746.     }
  1747.  
  1748.     /**
  1749.     * Wrapper function for {@link imap_setflag_full}.  Sets various message flags.
  1750.     * Accepts an array of message ids and an array of flags to be set.
  1751.     *
  1752.     * The flags which you can set are "\\Seen", "\\Answered", "\\Flagged",
  1753.     * "\\Deleted", and "\\Draft" (as defined by RFC2060).
  1754.     *
  1755.     * Warning: POP3 mailboxes do not remember flag settings from connection to connection.
  1756.     *
  1757.     * @param    array  $mids        Array of message ids to set flags on.
  1758.     * @param    array  $flags       Array of flags to set on messages.
  1759.     * @param    int    $action      Flag operation toggle one of set|clear
  1760.     * @param    int    $options 
  1761.     *    (optional) sets the forth argument of {@link imap_setflag_full} or {@imap_clearflag_full}. 
  1762.     *
  1763.     * @return   BOOL 
  1764.     * @throws   Message IDs and Flags are to be supplied as arrays.  Remedy: place message ids
  1765.     *            and flags in arrays.
  1766.     * @access   public
  1767.     * @see      imap_setflag_full
  1768.     * @see      imap_clearflag_full
  1769.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/setFlags
  1770.     */
  1771.     function setFlags($mids$flags$action 'set')
  1772.     {
  1773.         if (!is_array($mids)) {
  1774.             $this->error->push(Mail_IMAPv2_ERROR_ARGUMENT_REQUIRES_ARRAY'error'array('arg' => '$mids'));
  1775.             return false;
  1776.         }
  1777.         if (!is_array($flags)) {
  1778.             $this->error->push(Mail_IMAPv2_ERROR_ARGUMENT_REQUIRES_ARRAY'error'array('arg' => '$flags'));
  1779.             return false;
  1780.         }
  1781.         switch ($action{
  1782.             case 'set':
  1783.                 $func 'imap_setflag_full';
  1784.                 break;
  1785.             case 'clear':
  1786.                 $func 'imap_clearflag_full';
  1787.                 break;
  1788.             default:
  1789.                 $this->error->push(Mail_IMAPv2_ERROR_INVALID_ACTION'error'array('action' => $action'arg' => '$action'));
  1790.                 return false;
  1791.         }
  1792.         $opt (isset($this->option[$action.'flag_full']))$this->option[$action.'flag_full': null;
  1793.         return @$func($this->mailboximplode(','$mids)implode(' '$flags)$opt);
  1794.     }
  1795.  
  1796.     /**
  1797.     * Wrapper method for imap_list.  Calling on this function will return a list of mailboxes.
  1798.     * This method receives the host argument automatically via $this->connect in the
  1799.     * $this->mailboxInfo['host'] variable if a connection URI is used.
  1800.     *
  1801.     * @param    string  (optional) host name.
  1802.     * @return   array|false  list of mailboxes on the current server.
  1803.     * @access   public
  1804.     * @see      imap_list
  1805.     * @tutorial http://www.smilingsouls.net/Mail_IMAP?content=Mail_IMAP/getMailboxes
  1806.     */
  1807.     function getMailboxes($host = null$pattern '*'$rtn = true)
  1808.     {
  1809.         if (empty($host&& !isset($this->mailboxInfo['host'])) {
  1810.             $this->error->push(Mail_IMAPv2_ERROR'error'null'Supplied host is not valid!');
  1811.             return false;
  1812.         else if (empty($host&& isset($this->mailboxInfo['host'])) {
  1813.             $host $this->mailboxInfo['host'];
  1814.         }
  1815.  
  1816.         if ($list @imap_list($this->mailbox$host$pattern)) {
  1817.             if (is_array($list)) {
  1818.                 foreach ($list as $key => $val{
  1819.                    $mb[$keystr_replace($host''imap_utf7_decode($val));
  1820.                 }
  1821.             }
  1822.         else {
  1823.             $this->error->push(Mail_IMAPv2_ERROR'error'null'Cannot fetch mailbox names.');
  1824.             return false;
  1825.         }
  1826.  
  1827.         if ($rtn{
  1828.            return $mb;
  1829.         else {
  1830.             $this->mailboxInfo = array_merge($this->mailboxInfo$mb);
  1831.         }
  1832.     }
  1833. }
  1834. ?>

Documentation generated on Mon, 11 Mar 2019 14:30:27 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.