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

Source for file IMAP.php

Documentation is available at IMAP.php

  1. <?php
  2.  
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Author: Richard York <richy@smilingsouls.net>                        |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id
  20.  
  21. require_once 'PEAR.php';
  22.  
  23. // {{{ constants
  24. // {{{ Mail_IMAP::getBody action options
  25. define('MAIL_IMAP_BODY'0);
  26. define('MAIL_IMAP_LITERAL'1);
  27. define('MAIL_IMAP_LITERAL_DECODE'2);
  28. define('MAIL_IMAP_SET_FLAGS'3);
  29. define('MAIL_IMAP_CLEAR_FLAGS'4);
  30. // }}}
  31. // }}}
  32.  
  33. /**
  34. * Mail_IMAP provides a simplified backend for working with the c-client (IMAP) extension.
  35. * It serves as an OO wrapper for commonly used c-client functions.
  36. * It provides structure and header parsing as well as body retrieval.
  37. *
  38. * This package requires the c-client extension.  To download the latest version of
  39. * the c-client extension goto: http://www.php.net/imap.
  40. *
  41. * PEAR PREREQUISITES:
  42. *   Net_URL (Required if you will be using a URI abstraction to connect.)
  43. *
  44. * Known Bugs:
  45. *   Potential bugs may arise from the detection of certain multipart/* messages.
  46. *   Application parses and adjusts for anomalies in multipart/mixed,
  47. *   multipart/related and multipart/alternative messages.  Bugs may arise from
  48. *   untested and unincluded multipart message types, multipart/parallel,
  49. *   multipart/report, multipart/signed and multipart/digest.  If you happen
  50. *   across a problem related to one of the untested message types, please mail a
  51. *   copy of the message (if possible) to demo@smilingsouls.net where I may
  52. *   analyze the message structure and include it in the class.  Be sure to include
  53. *   Mail_IMAP (multipart/*) in the subject line so that I know the message isn't
  54. *   SPAM and don't delete it.
  55. *
  56. * Having trouble finding the example files?
  57. *   Examples are located in the PEAR install directory under /docs/Mail_IMAP/examples
  58. *
  59. * Extended documentation available at:
  60. *   http://www.spicypeanut.net
  61. *
  62. @author       Richard York <richy@smilingsouls.net>
  63. @category     Mail
  64. @package      Mail_IMAP
  65. @license      PHP
  66. @version      1.0.0RC1
  67. @copyright    (c) Copyright 2004, Richard York, All Rights Reserved.
  68. @since        PHP 4.2.0
  69. *
  70. @example      examples/IMAP.inbox.php
  71. *    Mail_IMAP Inbox
  72. *
  73. @example      examples/IMAP.message.php
  74. *    Mail_IMAP Message
  75. *
  76. @example      examples/IMAP.connection_wizard.php
  77. *    Mail_IMAP Connection Wizard
  78. *
  79. @example      examples/IMAP.connection_wizard_example.php
  80. *    Mail_IMAP Connection Wizard
  81. *
  82. @todo imap_list
  83. @todo imap_mail_copy
  84. @todo imap_mail_move
  85. */
  86.  
  87. // {{{ class Mail_IMAP
  88. class Mail_IMAP {
  89.  
  90.     // {{{ properties
  91.     /**
  92.      * Contains the imap resource stream.
  93.      * @var     resource $mailbox 
  94.      * @access  public
  95.      */
  96.     var $mailbox;
  97.  
  98.     /**
  99.      * Contains information about the current mailbox.
  100.      * @var     array $mailboxInfo 
  101.      * @access  public
  102.      */
  103.     var $mailboxInfo;
  104.  
  105.     /**
  106.      * (string) contains the various possible data types.
  107.      * @var     array $_dataTypes 
  108.      * @access  private
  109.      */
  110.     var $_dataTypes = array('text''multipart''message''application''audio''image''video''other');
  111.  
  112.     /**
  113.      * (string) Contains the various possible encoding types.
  114.      * @var     array $_encodingTypes 
  115.      * @access  private
  116.      */
  117.     var $_encodingTypes = array('7bit''8bit''binary''base64''quoted-printable''other');
  118.  
  119.     // --------------------------ALL MESSAGE PARTS-----------------------------
  120.     /**
  121.      * (object) Contains the object returned by {@link imap_fetchstructure}.
  122.      * @var     array $_structure 
  123.      * @access  private
  124.      */
  125.     var $_structure;
  126.  
  127.     /**
  128.      * (str) Contains all of the part ids for a given message.
  129.      * @var     array $_pid 
  130.      * @access  private
  131.      */
  132.     var $_pid;
  133.  
  134.     /**
  135.      * (string) Contains all of the part mime types for a given message.
  136.      * @var     array $_ftype 
  137.      * @access  private
  138.      */
  139.     var $_ftype;
  140.  
  141.     /**
  142.      * (int) Contains the file size in bytes for message parts.
  143.      * @var     array $_fsize 
  144.      * @access  private
  145.      */
  146.     var $_fsize;
  147.  
  148.     /**
  149.      * (str) Contains the original file name for a message part (if any).
  150.      * @var     array $_fname 
  151.      * @access  private
  152.      */
  153.     var $_fname;
  154.  
  155.     /**
  156.      * (string) Contains the part disposition inline | attachment.
  157.      * @var     array $_disposition 
  158.      * @access  private
  159.      */
  160.     var $_disposition;
  161.  
  162.     /**
  163.      * (str) Contains the part encoding.
  164.      * @var     array $_encoding 
  165.      * @access  private
  166.      */
  167.     var $_encoding;
  168.  
  169.     /**
  170.      * (str) Contains the part id for multipart/related (if any).
  171.      * @var     array $_inlineId 
  172.      * @access  private
  173.      */
  174.     var $_inlineId;
  175.  
  176.     /**
  177.      * (bool) Determines whether the current part has attachments.
  178.      * @var     array $_hasAttachments 
  179.      * @access  private
  180.      */
  181.     var $_hasAttachments;
  182.  
  183.     // --------------------------INLINE MESSAGE PARTS-----------------------------
  184.     /**
  185.      * (str) Inline part id.
  186.      * @var     array $inPid 
  187.      * @access  public
  188.      */
  189.     var $inPid;
  190.  
  191.     /**
  192.      * (str) Inline part MIME type.
  193.      * @var     array $inFtype 
  194.      * @access  public
  195.      */
  196.     var $inFtype;
  197.  
  198.     /**
  199.      * (int) Inline file size of the part in bytes.
  200.      * @var     array $inFsize 
  201.      * @access  public
  202.      */
  203.     var $inFsize;
  204.  
  205.     /**
  206.      * (int) Inline file name of the part, if any.
  207.      * @var     array $inFname 
  208.      * @access  public
  209.      */
  210.     var $inFname;
  211.     
  212.     /**
  213.      * (bool) Inline part has attachments?
  214.      * @var     array $inHasAttach 
  215.      * @access  public
  216.      */
  217.     var $inHasAttach;
  218.  
  219.     /**
  220.      * (str) Inline CID for multipart/related.
  221.      * @var     array $inInlineId 
  222.      * @access  public
  223.      */
  224.     var $inInlineId;
  225.  
  226.     // --------------------------ATTACHMENT MESSAGE PARTS-----------------------------
  227.     /**
  228.      * (str) Attachment part id.
  229.      * @var     array $attachPid 
  230.      * @access  public
  231.      */
  232.     var $attachPid;
  233.  
  234.     /**
  235.      * (str) Attachment MIME type.
  236.      * @var     array $attachFtype 
  237.      * @access  public
  238.      */
  239.     var $attachFtype;
  240.  
  241.     /**
  242.      * (int) Attachment file size in bytes.
  243.      * @var     array $attachFsize 
  244.      * @access  public
  245.      */
  246.     var $attachFsize;
  247.  
  248.     /**
  249.      * (str) Attachment original file name (if any, if not file name is empty string).
  250.      * @var     array $attachFname 
  251.      * @access  public
  252.      */
  253.     var $attachFname;
  254.  
  255.     /**
  256.      * (bool) Attachment has attachments?
  257.      * @var     array $attachHasAttach 
  258.      * @access  public
  259.      */
  260.     var $attachHasAttach;
  261.  
  262.     // -------------------------- MESSAGE HEADERS -----------------------------
  263.     /**
  264.      * (str) Contains raw message headers fetched from {@link imap_fetchbody}
  265.      * or {@link imap_fetchheader} depending on which message part is being retrieved.
  266.      * @var     array $rawHeaders 
  267.      * @access  public
  268.      */
  269.     var $rawHeaders;
  270.  
  271.     /**
  272.      * (array)(mixed) Associative array containing information gathered by {@link imap_headerinfo}
  273.      * or {@link imap_rfc822_parse_headers}.
  274.      * @var    header array $header
  275.      */
  276.     var $header;
  277.     // }}}
  278.  
  279.     // {{{ constructor
  280.     /**
  281.     * Constructor. Optionally set the IMAP resource stream.
  282.     *
  283.     * If IMAP connection arguments are not supplied, returns NULL.  Accepts
  284.     * a URI abstraction of the standard imap_open connection argument
  285.     * (see {@link connect}) or the imap resource indicator.
  286.     *
  287.     * @param     string         $connect  (optional) server URL to connect to
  288.     * @param     int            $options  (optional) options see imap_open
  289.     * @access    public
  290.     * @return    BOOL|NULL|PEAR_Error
  291.     * @see       connect
  292.     * @see       imap_open
  293.     */
  294.     function Mail_IMAP($connection = NULL$options = NULL)
  295.     {
  296.         if (is_resource($connection)) {
  297.             if (get_resource_type($connection== 'imap'{
  298.                 $this->mailbox = $connection;
  299.                 return TRUE;
  300.             else {
  301.                 return PEAR::raiseError('Error: Supplied resource is not a valid IMAP stream.');
  302.             }
  303.         else {
  304.             return ($connection == NULL)? NULL : Mail_IMAP::connect($connection$options);
  305.         }
  306.     }
  307.     // }}}
  308.  
  309.     // {{{ connect()
  310.     /**
  311.     * Wrapper method for {@link imap_open}.  Accepts a URI abstraction in
  312.     * the following format: imap://user:pass@mail.example.com:143/INBOX#notls
  313.     * instead of the standard connection arguments used in imap_open.
  314.     * Replace the protocol with one of pop3|pop3s imap|imaps nntp|nntps.
  315.     * Place intial folder in the file path portion, and optionally append
  316.     * tls|notls|novalidate-cert in the anchor portion of the URL.  A port
  317.     * number is optional, however, leaving it off could lead to a serious
  318.     * degradation in preformance.
  319.     *
  320.     * Examples of a well-formed connection argument:
  321.     *
  322.     * For IMAP:        imap://user:pass@mail.example.com:143/INBOX
  323.     *
  324.     * For IMAP SSL:    imaps://user:pass@example.com:993/INBOX
  325.     *
  326.     * For POP3:        pop3://user:pass@mail.example.com:110/INBOX
  327.     *
  328.     * For POP3 SSL:    pop3s://user:pass@mail.example.com:993/INBOX
  329.     *
  330.     * For NNTP:        nntp://user:pass@mail.example.com:119/comp.test
  331.     *
  332.     * For 'notls' OR 'novalidate-cert' append to the URL as an anchor.
  333.     * For 'tls' use secure protocol and add the 'tls' option to the anchor.
  334.     *
  335.     * Examples:
  336.     *
  337.     * For notls:       imap://user:pass@mail.example.com:143/INBOX#notls
  338.     *
  339.     * For tls:         imaps://user:pass@mail.example.com:143/INBOX#tls
  340.     *
  341.     * tls no-validate: imaps://user:pass@mail.example.com:143/INBOX#tls/novalidate-cert
  342.     *
  343.     * ssl no-validate: imaps://user:pass@mail.example.com:143/INBOX#novalidate-cert
  344.     *
  345.     * If the username is an email address or contains invalid URL characters,
  346.     * urlencode the username portion of the string before passing it.
  347.     *
  348.     * Use the IMAP.connection_wizard_example.php file to automatically detect
  349.     * the correct URI to pass to this function.  This file is located in the
  350.     * examples directory.
  351.     *
  352.     * @param    string           $connect   server URL
  353.     * @param    int              (optional) options
  354.     * @return   PEAR_Error|TRUE
  355.     * @access   public
  356.     * @see      imap_open
  357.     */
  358.     function connect($connect$options = NULL)
  359.     {
  360.         if (!class_exists('Net_URL')) {
  361.             require_once 'Net/URL.php';
  362.         }
  363.  
  364.         $url =new Net_URL($connect);
  365.  
  366.         $connect  '{'.$url->host;
  367.  
  368.         if (!empty($url->port)) {
  369.             $connect .= ':'.$url->port;
  370.         }
  371.  
  372.         $secure   ('tls' == substr($url->anchor03))'' '/ssl';
  373.         $connect .= ('s' == (substr($url->protocol-1)))'/'.substr($url->protocol04).$secure '/'.$url->protocol;
  374.  
  375.         if (!empty($url->anchor)) {
  376.             $connect .= '/'.$url->anchor;
  377.         }
  378.  
  379.         $connect .= '}';
  380.  
  381.         // Trim off the leading slash '/'
  382.         if (!empty($url->path)) {
  383.             $connect .= substr($url->path1(strlen($url->path- 1));
  384.         }
  385.  
  386.         $this->mailboxInfo['user']   urldecode($url->user);
  387.         $this->mailboxInfo['folder'$url->path;
  388.  
  389.         if ($options == NULL{
  390.             return (FALSE === ($this->mailbox = @imap_open($connecturldecode($url->user)$url->pass)))? PEAR::raiseError('Mail_IMAP::connect, unable to build a connection to the specified mail server.': TRUE;
  391.         else {
  392.             return (FALSE === ($this->mailbox = @imap_open($connecturldecode($url->user)$url->pass$options)))? PEAR::raiseError('Mail_IMAP::connect, unable to build a connection to the specified mail server.': TRUE;
  393.         }
  394.     }
  395.     // }}}
  396.  
  397.     // {{{ close()
  398.     /**
  399.     * Wrapper method for {@link imap_close}.  Close the IMAP resource stream.
  400.     *
  401.     * @param    int           $options    (optional) sets the second argument of imap_close
  402.     * @return   PEAR_Error|TRUE
  403.     * @access   public
  404.     * @see      imap_close
  405.     */
  406.     function close($options = NULL)
  407.     {
  408.         if ($options == NULL{
  409.              return (@imap_close($this->mailbox))? TRUE : PEAR::raiseError('Mail_IMAP::close, unable to close the connection to the mail server.');
  410.         else {
  411.              return (@imap_close($this->mailbox$options))? TRUE : PEAR::raiseError('Mail_IMAP::close, unable to close the connection to the mail server.');
  412.         }
  413.     }
  414.     // }}}
  415.  
  416.     // {{{ messageCount()
  417.     /**
  418.     * Wrapper method for {@link imap_num_msg}.  Calling on this function will reset the IMAP error
  419.     * stack (if mailbox is empty). {@link imap_errors} is called to supress a NOTICE level error,
  420.     * mailbox is empty, which isn't an error state.  For debugging, comment out the call to
  421.     * imap_errors.
  422.     *
  423.     * @return   int mailbox message count
  424.     * @access   public
  425.     * @see      imap_num_msg
  426.     */
  427.     function messageCount()
  428.     {
  429.         if (!$message_count @imap_num_msg($this->mailbox)) {
  430.             $errors = imap_errors();  // Gets rid of the annoying mailbox is empty error!
  431.             $message_count "0";
  432.         }
  433.  
  434.         return $message_count;
  435.     }
  436.     // }}}
  437.  
  438.     // {{{ _declareParts()
  439.     /**
  440.     * Gather message information returned by {@link imap_fetchstructure} and recursively iterate
  441.     * through each parts array.  Concatenate part numbers in the following format `1.1`
  442.     * each part id is separated by a period, each referring to a part or subpart of a
  443.     * multipart message.  Create part numbers as such that they are compatible with
  444.     * {@link imap_fetchbody}.
  445.     *
  446.     * @param    int           &$mid         message id
  447.     * @param    array         $sub_part     recursive
  448.     * @param    string        $sub_pid      recursive parent part id
  449.     * @param    int           $n            recursive counter
  450.     * @param    bool          $is_sub_part  recursive
  451.     * @param    bool          $skip_part    recursive
  452.     * @return   mixed 
  453.     * @access   private
  454.     * @see      imap_fetchstructure
  455.     * @see      imap_fetchbody
  456.     */
  457.     function _declareParts(&$mid$sub_part = NULL$sub_pid = NULL$n = 0$is_sub_part = FALSE$skip_part = FALSE)
  458.     {
  459.         if (!is_array($sub_part)) {
  460.             $this->_structure[$mid= imap_fetchstructure($this->mailbox$mid);
  461.         }
  462.  
  463.         if (isset($this->_structure[$mid]->parts|| is_array($sub_part)) {
  464.  
  465.             if ($is_sub_part == FALSE{
  466.                 $parts $this->_structure[$mid]->parts;
  467.             else {
  468.                 $parts $sub_part;
  469.                 $n++;
  470.             }
  471.  
  472.             for ($p = 0$i = 1; $p count($parts)$n++$p++$i++{
  473.                 // Skip the following...
  474.                 // multipart/mixed!
  475.                 // subsequent multipart/alternative if this part is message/rfc822
  476.                 // multipart/related
  477.                 //
  478.                 // Have noticed the existence of serveral other multipart/* types of messages
  479.                 // but have yet had the opportunity to test on those.
  480.                 $ftype        (empty($parts[$p]->type))?    $this->_dataTypes[0].'/'.strtolower($parts[$p]->subtype$this->_dataTypes[$parts[$p]->type].'/'.strtolower($parts[$p]->subtype);
  481.                 $skip_next    ($ftype == 'message/rfc822')? TRUE : FALSE;
  482.  
  483.                 if ($ftype == 'multipart/mixed' || $skip_part == TRUE && $ftype == 'multipart/alternative' || $ftype == 'multipart/related'{
  484.                     $n--;
  485.                     $skipped = TRUE;
  486.                 else {
  487.  
  488.                     $skipped = FALSE;
  489.  
  490.                     $this->_pid[$mid][$n]       ($is_sub_part == FALSE)$i $sub_pid.'.'.$i;
  491.                     $this->_ftype[$mid][$n]     $ftype;
  492.                     $this->_encoding[$mid][$n]  (empty($parts[$p]->encoding))$this->_encodingTypes[0$this->_encodingTypes[$parts[$p]->encoding];
  493.                     $this->_fsize[$mid][$n]     (!isset($parts[$p]->bytes|| empty($parts[$p]->bytes))? 0 : $parts[$p]->bytes;
  494.  
  495.                     // Force inline disposition if none is present
  496.                     if ($parts[$p]->ifdisposition == TRUE{
  497.                         $this->_disposition[$mid][$nstrtolower($parts[$p]->disposition);
  498.                         if (strtolower($parts[$p]->disposition== 'attachment'{
  499.                             if ($parts[$p]->ifdparameters == TRUE{
  500.                                 $params $parts[$p]->dparameters;
  501.                                 foreach ($params as $param{
  502.                                     if (strtolower($param->attribute== 'filename'{
  503.                                         $this->_fname[$mid][$n$param->value;
  504.                                         break;
  505.                                     }
  506.                                 }
  507.                             }
  508.                         }
  509.                     else {
  510.                         $this->_disposition[$mid][$n'inline';
  511.                     }
  512.  
  513.                     if ($parts[$p]->ifid == TRUE{
  514.                         $this->inline_id[$mid][$n$parts[$p]->id;
  515.                     }
  516.                 }
  517.  
  518.                 if (isset($parts[$p]->parts&& is_array($parts[$p]->parts)) {
  519.                     if ($skipped == FALSE{
  520.                         $this->_hasAttachments[$mid][$n= TRUE;
  521.                     }
  522.  
  523.                     $n Mail_IMAP::_declareParts($mid$parts[$p]->parts$this->_pid[$mid][$n]$nTRUE$skip_next);
  524.  
  525.                 else if ($skipped == FALSE{
  526.                     $this->_hasAttachments[$mid][$n= FALSE;
  527.                 }
  528.             }
  529.  
  530.             if ($is_sub_part == TRUE{
  531.                 return $n;
  532.             }
  533.  
  534.          else {
  535.  
  536.              // $parts is not an array... message is flat
  537.             $this->_pid[$mid][0= 1;
  538.  
  539.             if (empty($this->_structure[$mid]->type)) {
  540.                 $this->_structure[$mid]->type        = (int) 0;
  541.             }
  542.  
  543.             if (isset($this->_structure[$mid]->subtype)) {
  544.                 $this->_ftype[$mid][0]               $this->_dataTypes[$this->_structure[$mid]->type].'/'.strtolower($this->_structure[$mid]->subtype);
  545.             }
  546.  
  547.             if (empty($this->_structure[$mid]->encoding)) {
  548.                 $this->_structure[$mid]->encoding    = (int) 0;
  549.             }
  550.  
  551.             $this->_encoding[$mid][0]                $this->_encodingTypes[$this->_structure[$mid]->encoding];
  552.  
  553.             if (isset($this->_structure[$mid]->bytes)) {
  554.                 $this->_fsize[$mid][0]               strtolower($this->_structure[$mid]->bytes);
  555.             }
  556.  
  557.             $this->_disposition[$mid][0]             'inline';
  558.             $this->_hasAttachments[$mid][0]          = FALSE;
  559.         }
  560.  
  561.         return;
  562.     }
  563.     // }}}
  564.  
  565.     // {{{ _checkIfParsed()
  566.     /**
  567.     * Checks if the part has been parsed, if not calls on _declareParts to
  568.     * parse the message.
  569.     *
  570.     * @param    int          &$mid         message id
  571.     * @return   void 
  572.     * @access   private
  573.     */
  574.     function _checkIfParsed(&$mid)
  575.     {
  576.         if (!isset($this->_pid[$mid])) {
  577.            Mail_IMAP::_declareParts($mid);
  578.         }
  579.         return;
  580.     }
  581.     // }}}
  582.  
  583.     // {{{ getParts()
  584.     /**
  585.     * sets up member variables containing inline parts and attachments for a specific part
  586.     * in member variable arrays beginning with 'in' and 'attach'.
  587.     * If inline parts are present, sets {@link $inPid}{@link $inFtype}{@link $inFsize},
  588.     * {@link $inHasAttach}{@link $inInlineId} (if an inline CID is specified).
  589.     * If attachments are present, sets, {@link $attachPid}{@link $attachFsize}{@link $attachHasAttach},
  590.     * {@link $attachFname} (if a filename is present, empty string otherwise).
  591.     *
  592.     * Typically the text/html part is displayed by default by a message viewer, this part is
  593.     * excluded from the inline member variable arrays thourgh $excludeMime by default.  If
  594.     * $getInline is TRUE the text/plain alternative part will be returned in the inline array
  595.     * and may be included as an attachment.  Useful for mail developement/debugging of multipart
  596.     * messages.
  597.     *
  598.     * @param    int           &$mid         message id
  599.     * @param    int           &$pid         part id
  600.     * @param    string        $MIME 
  601.     *        (optional) values: text/plain|text/html, the part MIME type that will be
  602.     *        retrieved by default.
  603.     *
  604.     * @param    bool          $getAlternative 
  605.     *        (optional) include the plain text alternative part in the created inline parts
  606.     *        array.
  607.     *
  608.     * @return   bool 
  609.     * @access   public
  610.     * @since    PHP 4.2.0
  611.     */
  612.     function getParts(&$mid&$pid$MIME 'text/html'$getAlternative = TRUE)
  613.     {
  614.         Mail_IMAP::_checkIfParsed($mid);
  615.  
  616.         if (count($this->_pid[$mid]== 1{
  617.             return TRUE;
  618.         }
  619.  
  620.         // retrieve key for this part, so that the information may be accessed
  621.         if (FALSE !== ($i array_search($pid$this->_pid[$mid]))) {
  622.             if ($pid == Mail_IMAP::getDefaultPid($mid)) {
  623.                 Mail_IMAP::_scanMultipart($mid$pid$i$MIME'add''top'4$getAlternative);
  624.             else if ($this->_ftype[$mid][$i== 'message/rfc822'{
  625.                 Mail_IMAP::_scanMultipart($mid$pid$i$MIME'add''all'2$getAlternative);
  626.             }
  627.         else {
  628.             PEAR::raiseError('Mail_IMAP::getParts was unable to retrieve a valid part id from the pid passed.'nullPEAR_ERROR_TRIGGERE_USER_WARNING'mid: '.$mid.' pid: '.$pid);
  629.             return FALSE;
  630.         }
  631.  
  632.         return TRUE;
  633.     }
  634.     // }}}
  635.  
  636.     function _scanMultipart(&$mid&$pid&$i$MIME$action 'add'$lookAt 'all'$pidAdd = 2$getAlternative = TRUE)
  637.     {
  638.         // Find subparts, create variables
  639.         // Create inline parts first, and attachments second
  640.  
  641.         // Get all top level parts, with the exception of the part currently being viewed
  642.         // If top level part contains multipart/alternative go into that subpart to
  643.         // retrieve the other inline message part to display
  644.  
  645.         // If this part is message/rfc822 get subparts that begin with this part id
  646.         // Skip multipart/alternative message part
  647.         // Find the displayable message, get plain/text part if $getInline is TRUE
  648.  
  649.         if ($action == 'add'{
  650.            $excludeMIME $MIME;
  651.            $MIME        ($excludeMIME == 'text/plain')'text/html' 'text/plain';
  652.            $in          = 0;
  653.            $a           = 0;
  654.         else if ($action == 'get'{
  655.            $excludeMIME = NULL;
  656.         }
  657.  
  658.         $pid_len strlen($pid);
  659.  
  660.         foreach ($this->_pid[$midas $p => $id{
  661.             switch ($lookAt{
  662.                 case 'all':       $condition (strlen($this->_pid[$mid][$p]== ($pid_len + 2&& $pid == substr($this->_pid[$mid][$p]0$pid_len)); break;
  663.                 case 'multipart'$condition ((strlen($this->_pid[$mid][$p]== $pid_len + 2&& ($pid == substr($this->_pid[$mid][$p]0)));         break;
  664.                 default:          $condition (strlen($this->_pid[$mid][$p]== 1);
  665.             }
  666.  
  667.             if ($condition == TRUE{
  668.                 if ($this->_ftype[$mid][$p== 'multipart/alternative'{
  669.                     foreach ($this->_pid[$midas $mp => $mpid{
  670.                         // Part must begin with last matching part id and be two levels in
  671.                         // Top level parser looks at pid_length + 4 -- is this a bug?
  672.                         if (($this->_ftype[$mid][$mp== $MIME && $getAlternative == TRUE && (strlen($this->_pid[$mid][$mp]== ($pid_len $pidAdd)) && ($pid == substr($this->_pid[$mid][$mp]0strlen($this->_pid[$mid][$p]))))) {
  673.                             if ($action == 'add'{
  674.                                  Mail_IMAP::_addInlinePart($in$mid$mp);
  675.                                  break;
  676.                             else if ($action == 'get'{
  677.                                  return $this->_pid[$mid][$mp];
  678.                             }
  679.                         else if ($this->_ftype[$mid][$mp== 'multipart/alternative' && $action == 'get'{
  680.                             // Need to match this PID to next level in
  681.                             $pid     $this->_pid[$mid][$mp];
  682.                             $pid_len strlen($this->_pid[$mid][$mp]);
  683.                             $pidAdd  = 4;
  684.                             continue;
  685.                         }
  686.                     }
  687.                 else if ($this->_disposition[$mid][$p== 'inline'{
  688.                     if ($action == 'add' && $this->_ftype[$mid][$p!= $excludeMIME && $pid != $this->_pid[$mid][$p]{
  689.                         Mail_IMAP::_addInlinePart($in$mid$p);
  690.                     else if ($action == 'get' && $this->_ftype[$mid][$p== $MIME{
  691.                         return $this->_pid[$mid][$p];
  692.                     }
  693.                 else if ($action == 'add' && $this->_disposition[$mid][$p== 'attachment'{
  694.                     Mail_IMAP::_addAttachment($a$mid$p);
  695.                 }
  696.             }
  697.         }
  698.         return FALSE;
  699.     }
  700.  
  701.     // {{{ unsetParts()
  702.     /**
  703.     * Destroys variables set by {@link getParts} and _declareParts.
  704.     *
  705.     * @param    integer  &$mid   message id
  706.     * @return   void 
  707.     * @access   public
  708.     * @see      getParts
  709.     */
  710.     function unsetParts(&$mid)
  711.     {
  712.         unset($this->inPid[$mid]);
  713.         unset($this->inFtype[$mid]);
  714.         unset($this->inFsize[$mid]);
  715.         unset($this->inHasAttach[$mid]);
  716.         unset($this->inInlineId[$mid]);
  717.  
  718.         unset($this->attachPid[$mid]);
  719.         unset($this->attachFtype[$mid]);
  720.         unset($this->attachFsize[$mid]);
  721.         unset($this->attachFname[$mid]);
  722.         unset($this->attachHasAttach[$mid]);
  723.  
  724.         unset($this->_structure[$mid]);
  725.         unset($this->_pid[$mid]);
  726.         unset($this->_disposition[$mid]);
  727.         unset($this->_encoding[$mid]);
  728.         unset($this->_ftype[$mid]);
  729.         unset($this->_fsize[$mid]);
  730.         unset($this->_fname[$mid]);
  731.         unset($this->_inlineId[$mid]);
  732.         unset($this->_hasAttachments[$mid]);
  733.  
  734.         return;
  735.     }
  736.     // }}}
  737.  
  738.     // {{{ _addInlinePart()
  739.     /**
  740.     * Adds information to the member variable inline parts arrays.
  741.     *
  742.     * @param    int     &$in   offset inline counter
  743.     * @param    int     &$mid  message id
  744.     * @param    int     &$i    offset structure reference counter
  745.     * @return   void 
  746.     * @access   private
  747.     */
  748.     function _addInlinePart(&$in&$mid&$i)
  749.     {
  750.         if (isset($this->_fname[$mid][$i]&& !empty($this->_fname[$mid][$i])) {
  751.             $this->inFname[$mid][$in$this->_fname[$mid][$i];
  752.         }
  753.  
  754.         $this->inPid[$mid][$in]            $this->_pid[$mid][$i];
  755.         $this->inFtype[$mid][$in]          $this->_ftype[$mid][$i];
  756.         $this->inFsize[$mid][$in]          $this->_fsize[$mid][$i];
  757.         $this->inHasAttach[$mid][$in]      $this->_hasAttachments[$mid][$i];
  758.  
  759.         if (isset($this->_inlineId[$mid][$i])) {
  760.             $this->inInlineId[$mid][$in]   $this->_inlineId[$mid][$i];
  761.         }
  762.  
  763.         $in++;
  764.  
  765.         return;
  766.     }
  767.     // }}}
  768.  
  769.     // {{{ _addAttachment()
  770.     /**
  771.     * Adds information to the member variable attachment parts arrays.
  772.     *
  773.     * @param    int     &$a    offset attachment counter
  774.     * @param    int     &$mid  message id
  775.     * @param    int     &$i    offset structure reference counter
  776.     * @return   void 
  777.     * @access   private
  778.     */
  779.     function _addAttachment(&$a&$mid&$i)
  780.     {
  781.         if (!isset($this->_fname[$mid][$i])) {
  782.             $this->_fname[$mid][$i'';
  783.         }
  784.  
  785.         $this->attachPid[$mid][$a]         $this->_pid[$mid][$i];
  786.         $this->attachFtype[$mid][$a]       $this->_ftype[$mid][$i];
  787.         $this->attachFsize[$mid][$a]       $this->_fsize[$mid][$i];
  788.         $this->attachFname[$mid][$a]       $this->_fname[$mid][$i];
  789.         $this->attachHasAttach[$mid][$a]   $this->_hasAttachments[$mid][$i];
  790.  
  791.         $a++;
  792.  
  793.         return;
  794.     }
  795.     // }}}
  796.  
  797.     // {{{ getRawMessage()
  798.     /**
  799.     * Returns entire unparsed message body.  See {@link imap_body} for options.
  800.     *
  801.     * @param    int     &$mid      message id
  802.     * @param    int     $options   flags
  803.     * @return   void 
  804.     * @access   public
  805.     * @see      imap_body
  806.     */
  807.     function getRawMessage(&$mid$options = NULL)
  808.     {
  809.         return ($options == NULL)? imap_body($this->mailbox$mid: imap_body($this->mailbox$mid$options);
  810.     }
  811.     // }}}
  812.  
  813.     // {{{ getBody()
  814.     /**
  815.     * Searches parts array set in Mail_IMAP::_declareParts() for a displayable message.
  816.     * If the part id passed is message/rfc822 looks in subparts for a displayable body.
  817.     * Attempts to return a text/html inline message part by default. And will
  818.     * automatically attempt to find a text/plain part if a text/html part could
  819.     * not be found.
  820.     *
  821.     * Returns an array containing three associative indices; 'ftype', 'fname' and
  822.     * 'message'.  'ftype' contains the MIME type of the message, 'fname', the original
  823.     * file name, if any, empty string otherwise.  And 'message', which contains the
  824.     * message body itself which is returned decoded from base64 or quoted-printable if
  825.     * either of those encoding types are specified, returns untouched otherwise.
  826.     * Returns FALSE on failure.
  827.     *
  828.     * @param    int     &$mid                    message id
  829.     * @param    string  $pid                     part id
  830.     * @param    int     $action 
  831.     *       (optional) options for body return.  Set to one of the following:
  832.     *       MAIL_IMAP_BODY (default), if part is message/rfc822 searches subparts for a
  833.     *       displayable body and returns the body decoded as part of an array.
  834.     *       MAIL_IMAP_LITERAL, return the message for the specified $pid without searching
  835.     *       subparts or decoding the message (may return unparsed message) body is returned
  836.     *       undecoded as a string.
  837.     *       MAIL_IMAP_LITERAL_DECODE, same as MAIL_IMAP_LITERAL, except message decoding is
  838.     *       attempted from base64 or quoted-printable encoding, returns undecoded string
  839.     *       if decoding failed.
  840.     *
  841.     * @param    string  $getPart 
  842.     *       (optional) one of text/plain or text/html, allows the specification of the default
  843.     *       part to return from multipart messages, text/html by default.
  844.     *
  845.     * @param    int     $options 
  846.     *       (optional) allows the specification of the forth argument of imap_fetchbody
  847.     *
  848.     * @return   array|string|FALSE
  849.     * @access   public
  850.     * @see      imap_fetchbody
  851.     * @see      Mail_IMAP::getParts
  852.     * @since    PHP 4.2.0
  853.     */
  854.     function getBody(&$mid$pid$action = 0$getPart 'text/html'$options = NULL$attempt = 1)
  855.     {
  856.         if ($action == MAIL_IMAP_LITERAL{
  857.             return ($options == NULL)? imap_fetchbody($this->mailbox$mid$pid: imap_fetchbody($this->mailbox$mid$pid$options);
  858.         }
  859.  
  860.         Mail_IMAP::_checkIfParsed($mid);
  861.  
  862.         if (FALSE !== ($i array_search($pid$this->_pid[$mid]))) {
  863.             if ($action == MAIL_IMAP_LITERAL_DECODE{
  864.                 $msg_body ($options == NULL)? imap_fetchbody($this->mailbox$mid$pid: imap_fetchbody($this->mailbox$mid$pid$options);
  865.                 return Mail_IMAP::_decodeMessage($msg_body$this->_encoding[$mid][$i]);
  866.             }
  867.  
  868.             // If this is an attachment, and the part is message/rfc822 update the pid to the subpart
  869.             // If this is an attachment, and the part is multipart/alternative update the pid to the subpart
  870.             if ($this->_ftype[$mid][$i== 'message/rfc822' || $this->_ftype[$mid][$i== 'multipart/alternative'{
  871.                 $new_pid ($this->_ftype[$mid][$i== 'message/rfc822')Mail_IMAP::_scanMultipart($mid$pid$i$getPart'get''all'2Mail_IMAP::_scanMultipart($mid$pid$i$getPart'get''multipart'2);
  872.  
  873.                 // if a new pid for text/html couldn't be found, try again, this time look for text/plain
  874.                 switch(TRUE{
  875.                     case (!empty($new_pid)):                             $pid $new_pid; break;
  876.                     case (empty($new_pid&& $getPart == 'text/html'):   return ($attempt == 1)Mail_IMAP::getBody($mid$pid$action'text/plain'$options2: FALSE;
  877.                     case (empty($new_pid&& $getPart == 'text/plain'):  return ($attempt == 1)Mail_IMAP::getBody($mid$pid$action'text/html'$options2: FALSE;
  878.                 }
  879.             }
  880.  
  881.             // Update the key for the new pid
  882.             if (!empty($new_pid)) {
  883.                 if (FALSE === ($i array_search($pid$this->_pid[$mid]))) {
  884.                     // Something's afoot!
  885.                     PEAR::raiseError('Mail_IMAP::getBody was unable to find a suitable replacement part ID for: '.$pid.'.  Message: '.$mid.' may be poorly formed or corrupted.'NULLPEAR_ERROR_TRIGGERE_USER_WARNING);
  886.                     return FALSE;
  887.                 }
  888.             }
  889.  
  890.             $msg_body ($options == NULL)? imap_fetchbody($this->mailbox$mid$pid: imap_fetchbody($this->mailbox$mid$pid$options);
  891.  
  892.             if ($msg_body == NULL{
  893.                 PEAR::raiseError('Mail_IMAP::getBody message body was NULL for pid: '.$pid.', is not a valid part number.'NULLPEAR_ERROR_TRIGGERE_USER_NOTICE);
  894.                 return FALSE;
  895.             }
  896.  
  897.             // Decode message.
  898.             // Because the body returned may not correspond with the original PID, return
  899.             // an array which also contains the MIME type and original file name, if any.
  900.             $body['message'Mail_IMAP::_decodeMessage($msg_body$this->_encoding[$mid][$i]);
  901.             $body['ftype']   $this->_ftype[$mid][$i];
  902.             $body['fname']   (isset($this->_fname[$mid][$i]))$this->_fname[$mid][$i'';
  903.  
  904.             return $body;
  905.         else {
  906.             PEAR::raiseError('Mail_IMAP::getBody was unable to retrieve message body, invalid part id: '.$pidNULLPEAR_ERROR_TRIGGERE_USER_WARNING);
  907.             return FALSE;
  908.         }
  909.  
  910.         return FALSE;
  911.     }
  912.     // }}}
  913.  
  914.     // {{{ _decodeMessage()
  915.     /**
  916.     * Decode a string from quoted-printable or base64 encoding.  If
  917.     * neither of those encoding types are specified, returns string
  918.     * untouched.
  919.     *
  920.     * @param    string  &$body           string to decode
  921.     * @param    string  &$encoding       encoding to decode from.
  922.     * @return   string 
  923.     * @access   private
  924.     */
  925.     function _decodeMessage(&$body&$encoding)
  926.     {
  927.         switch ($encoding{
  928.             case 'quoted-printable':  return imap_qprint($body);
  929.             case 'base64':            return imap_base64($body);
  930.             default:                  return $body;
  931.         }
  932.     }
  933.     // }}}
  934.  
  935.     // {{{ getDefaultPid()
  936.     /**
  937.     * Searches structure defined in Mail_IMAP::_declareParts for the top-level default message.
  938.     * Attempts to find a text/html default part, if no text/html part is found,
  939.     * automatically attempts to find a text/plain part. Returns the part id for the default
  940.     * top level message part on success. Returns FALSE on failure.
  941.     *
  942.     * @param    int     &$mid           message id
  943.     * @param    string  $getPart 
  944.     *      (optional) default MIME type to look for, one of text/html or text/plain
  945.     *      text/html by default.
  946.     * @return   string 
  947.     * @access   public
  948.     */
  949.     function getDefaultPid(&$mid$getPart 'text/html'$attempt = 1)
  950.     {
  951.         // Check to see if this part has already been parsed
  952.         Mail_IMAP::_checkIfParsed($mid);
  953.  
  954.         // Look for a text/html message part
  955.         // If no text/html message part was found look for a text/plain message part
  956.  
  957.         $part ($getPart == 'text/html')? array('text/html''text/plain': array('text/plain''text/html');
  958.  
  959.         foreach ($part as $mime{
  960.             if (0 !== count($msg_part array_keys($this->_ftype[$mid]$mime))) {
  961.                 foreach ($msg_part as $i{
  962.                     if ($this->_disposition[$mid][$i== 'inline' && strlen($this->_pid[$mid][$i]== 1{
  963.                         return $this->_pid[$mid][$i];
  964.                     }
  965.                 }
  966.             }
  967.         }
  968.  
  969.         // If no text/plain or text/html part was found
  970.         // Look for a multipart/alternative part
  971.  
  972.         foreach ($this->_pid[$midas $p => $id{
  973.             if (strlen($this->_pid[$mid][$p]== 1 && $this->_ftype[$mid][$p== 'multipart/alternative'{
  974.                 foreach ($this->_pid[$midas $mp => $mpid{
  975.                     if ($this->_ftype[$mid][$mp== $getPart && strlen($this->_pid[$mid][$mp]== 3 && $this->_pid[$mid][$p== substr($this->_pid[$mid][$mp]01)) {
  976.                         return $this->_pid[$mid][$mp];
  977.                     }
  978.                 }
  979.             }
  980.         }
  981.  
  982.         // if a text/html part was not found, call on the function again
  983.         // and look for text/plain
  984.         // if the application was unable to find a text/plain part
  985.  
  986.         switch ($getPart{
  987.             case 'text/html':  return ($attempt == 1)Mail_IMAP::getDefaultPid($mid'text/plain'2: FALSE;
  988.             case 'text/plain'return ($attempt == 1)Mail_IMAP::getDefaultPid($mid'text/html'2: FALSE;
  989.             default:           return FALSE;
  990.         }
  991.  
  992.         return FALSE;
  993.     }
  994.     // }}}
  995.  
  996.     // {{{ extractMIME()
  997.     /**
  998.     * Searches all message parts for the specified MIME type.  Use {@link getBody}
  999.     * with $action option MAIL_IMAP_LITERAL_DECODE to view MIME type parts retrieved.
  1000.     * If you need to access the MIME type with filename use normal {@link getBody}
  1001.     * with no action specified.
  1002.     *
  1003.     * Returns an array of part ids on success.
  1004.     * Returns FALSE if MIME couldn't be found, or on failure.
  1005.     *
  1006.     * @param    int     &$mid           message id
  1007.     * @param    string  $MIME           mime type to extract
  1008.     * @return   array|FALSE
  1009.     * @access   public
  1010.     */
  1011.     function extractMIME(&$mid$MIME)
  1012.     {
  1013.         Mail_IMAP::_checkIfParsed($mid);
  1014.  
  1015.         if (is_array($this->_ftype[$mid])) {
  1016.             if (0 !== count($pids array_keys($this->_ftype[$mid]$MIME))) {
  1017.                 foreach ($pids as $i{
  1018.                     $rtn[$this->_pid[$mid][$i];
  1019.                 }
  1020.             else {
  1021.                 $rtn = FALSE;
  1022.             }
  1023.         else {
  1024.             $rtn = FALSE;
  1025.         }
  1026.  
  1027.         return $rtn;
  1028.     }
  1029.     // }}}
  1030.  
  1031.     // {{{ getRawHeaders()
  1032.     /**
  1033.     * Set member variable {@link $rawHeaders} to contain Raw Header information
  1034.     * for a part.  Returns default header part id on success, returns FALSE on failure.
  1035.     *
  1036.     * @param    int     &$mid          message_id
  1037.     * @param    string  $pid           part id
  1038.     * @param    int     $options       flags/options for imap_fetchbody
  1039.     * @return   string|FALSE
  1040.     * @access   public
  1041.     * @see      imap_fetchbody
  1042.     * @see      getHeaders
  1043.     */
  1044.     function getRawHeaders(&$mid$pid$options = NULL)
  1045.     {
  1046.         // pid is modified in this function, so don't pass by reference (will create a logic error)
  1047.         if (FALSE !== ($pid Mail_IMAP::_defaultHeaderPid($mid$pid))) {
  1048.             if ($options == NULL{
  1049.                 $this->rawHeaders[$mid($pid == '0')? imap_fetchheader($this->mailbox$mid: imap_fetchbody($this->mailbox$mid$pid);
  1050.             else {
  1051.                 $this->rawHeaders[$mid($pid == '0')? imap_fetchheader($this->mailbox$mid: imap_fetchbody($this->mailbox$mid$pid$options);
  1052.             }
  1053.  
  1054.             return $pid;
  1055.         else {
  1056.             PEAR::raiseError('Mail_IMAP::getRawHeaders unable to retrieve headers, invalid part id: '.$pidNULLPEAR_ERROR_TRIGGERE_USER_WARNING);
  1057.             return FALSE;
  1058.         }
  1059.     }
  1060.     // }}}
  1061.  
  1062.     // {{{ getHeaders()
  1063.     /**
  1064.     * Set member variable containing header information.  Creates an array containing associative indices
  1065.     * referring to various header information.  Use {@link var_dump} or {@link print_r} on the {@link $header}
  1066.     * member variable to view information gathered by this function.
  1067.     *
  1068.     * @param    int     &$mid           message id
  1069.     * @param    string  &$pid           part id
  1070.     * @param    int     $from_length    (optional) from length for imap_headerinfo
  1071.     * @param    int     $subject_length (optional) subject length for imap_headerinfo
  1072.     * @param    string  $default_host   (optional) default host for imap_headerinfo & imap_rfc822_parse_headers
  1073.     * @param    int     $options        (optional) flags/options for imap_fetchbody
  1074.     * @return   BOOL 
  1075.     * @access   public
  1076.     * @see      getParts
  1077.     * @see      imap_fetchheader
  1078.     * @see      imap_fetchbody
  1079.     * @see      imap_headerinfo
  1080.     * @see      imap_rfc822_parse_headers
  1081.     */
  1082.     function getHeaders(&$mid&$pid$from_length = 1024$subject_length = 1024$default_host = NULL$options = NULL)
  1083.     {
  1084.         if (FALSE === ($hpid Mail_IMAP::getRawHeaders($mid$pid$options))) {
  1085.             return FALSE;
  1086.         }
  1087.  
  1088.         // $default_host contains the host information for addresses where it is not
  1089.         // present.  Specify it or attempt to use SERVER_NAME
  1090.         if ($default_host == NULL && isset($_SERVER['SERVER_NAME']&& !empty($_SERVER['SERVER_NAME'])) {
  1091.             $default_host $_SERVER['SERVER_NAME'];
  1092.         else if ($default_host == NULL{
  1093.             $default_host 'UNSPECIFIED-HOST-NAME';
  1094.         }
  1095.  
  1096.         // Parse the headers
  1097.         $header_info ($hpid == '0')? imap_headerinfo($this->mailbox$mid$from_length$subject_length$default_host: imap_rfc822_parse_headers($this->rawHeaders[$mid]$default_host);
  1098.  
  1099.         // Since individual member variable creation might create extra overhead,
  1100.         // and having individual variables referencing this data and the original
  1101.         // object would be too much as well, we'll just copy the object into an
  1102.         // associative array, preform clean-up on those elements that require it,
  1103.         // and destroy the original object after copying.
  1104.  
  1105.         if (!is_object($header_info)) {
  1106.             PEAR::raiseError('Mail_IMAP::getHeaders unable to retrieve header object, invalid part id: '.$pidNULLPEAR_ERROR_TRIGGERE_USER_WARNING);
  1107.             return FALSE;
  1108.         }
  1109.  
  1110.         $headers get_object_vars($header_info);
  1111.  
  1112.         foreach ($headers as $key => $value{
  1113.             if (!is_object($value&& !is_array($value)) {
  1114.                 $this->header[$mid][$key$value;
  1115.             }
  1116.         }
  1117.  
  1118.         // copy udate or create it from date string.
  1119.         $this->header[$mid]['udate'(isset($header_info->udate&& !empty($header_info->udate))$header_info->udate : strtotime($header_info->Date);
  1120.  
  1121.         // clean up addresses
  1122.         $line['from';
  1123.         $line['reply_to';
  1124.         $line['sender';
  1125.         $line['return_path';
  1126.         $line['to';
  1127.         $line['cc';
  1128.         $line['bcc';
  1129.  
  1130.         for ($i = 0; $i count($line)$i++{
  1131.             if (isset($header_info->$line[$i])) {
  1132.                 Mail_IMAP::_parseHeaderLine($mid$header_info->$line[$i]$line[$i]);
  1133.             }
  1134.         }
  1135.  
  1136.         // All possible information has been copied, destroy original object
  1137.         unset($header_info);
  1138.  
  1139.         return TRUE;
  1140.     }
  1141.     // }}}
  1142.  
  1143.     // {{{ _parseHeaderLine()
  1144.     /**
  1145.     * Parse header information from the given line and add it to the {@link $header}
  1146.     * array.  This function is only used by {@link getRawHeaders}.
  1147.     *
  1148.     * @param     string   &$line 
  1149.     * @param     string   $name 
  1150.     * @return    void 
  1151.     * @access    private
  1152.     */
  1153.     function _parseHeaderLine(&$mid&$line$name{
  1154.         if (isset($line&& count($line>= 1{
  1155.             $i = 0;
  1156.             foreach ($line as $object{
  1157.                 if (isset($object->personal)) {
  1158.                     $this->header[$mid][$name.'_personal'][$i$object->personal;
  1159.                 }
  1160.  
  1161.                 if (isset($object->mailbox&& isset($object->host)) {
  1162.                     $this->header[$mid][$name][$i$object->mailbox.'@'.$object->host;
  1163.                 }
  1164.                 $i++;
  1165.             }
  1166.         }
  1167.         return;
  1168.     }
  1169.     // }}}
  1170.  
  1171.     // {{{ _defaultHeaderPid()
  1172.     /**
  1173.     * Finds and returns a default part id for headers and matches any sub message part to
  1174.     * the appropriate headers.  Returns FALSE on failure and may return a value that
  1175.     * evaluates to false, use the '===' operator for testing this function's return value.
  1176.     *
  1177.     * @param    int     &$mid            message id
  1178.     * @param    string  $pid             part id
  1179.     * @return   string|FALSE
  1180.     * @access   private
  1181.     * @see      getHeaders
  1182.     * @see      getRawHeaders
  1183.     */
  1184.     function _defaultHeaderPid(&$mid$pid)
  1185.     {
  1186.         // pid is modified in this function, so don't pass by reference (will create a logic error)
  1187.         Mail_IMAP::_checkIfParsed($mid);
  1188.  
  1189.         // retrieve key for this part, so that the information may be accessed
  1190.         if (FALSE !== ($i array_search($pid$this->_pid[$mid]))) {
  1191.             // If this part is message/rfc822 display headers for this part
  1192.             if ($this->_ftype[$mid][$i== 'message/rfc822'{
  1193.                 $ret $pid.'.0';
  1194.             else if ($pid == Mail_IMAP::getDefaultPid($mid)) {
  1195.                 $ret '0';
  1196.             else {
  1197.                 $pid_len strlen($pid);
  1198.  
  1199.                 // Deeper searching may be required, go back to this part's parent.
  1200.                 if ($pid_len == 1{
  1201.                     $ret '0';
  1202.                 else if ($pid_len > 1{
  1203.                     // Pid should be at least 3 characters or more in length
  1204.                     if ($pid_len >= 3{
  1205.                         // Look at previous parts until a message/rfc822 part is found.
  1206.                         for ($len $pid_len - 2; $len > 0; $len -= 2{
  1207.                             foreach ($this->_pid[$midas $p => $aid{
  1208.                                 if ((strlen($this->_pid[$mid][$p]== $len && $this->_pid[$mid][$p== substr($pid0$len)) && ($this->_ftype[$mid][$p== 'message/rfc822')) {
  1209.                                     // Break iteration and return!
  1210.                                     return $this->_pid[$mid][$p].'.0';
  1211.                                 }
  1212.                             }
  1213.                         }
  1214.                         $ret ($pid_len == 3)'0' : FALSE;
  1215.                     else {
  1216.                         $ret = FALSE;
  1217.                     }
  1218.                 else {
  1219.                     $ret = FALSE;
  1220.                 }
  1221.             }
  1222.             return $ret;
  1223.         else {
  1224.             // Something's afoot!
  1225.             PEAR::raiseError('Mail_IMAP::_defaultHeaderPid unable to retrieve headers, invalid part id: '.$pidNULLPEAR_ERROR_TRIGGERE_USER_WARNING);
  1226.             return FALSE;
  1227.         }
  1228.     }
  1229.     // }}}
  1230.  
  1231.     // {{{ unsetHeaders()
  1232.     /**
  1233.     * Destroys variables set by {@link getHeaders}.
  1234.     *
  1235.     * @param    int     &$mid            message id
  1236.     * @return   void 
  1237.     * @access   public
  1238.     * @see      getHeaders
  1239.     */
  1240.     function unsetHeaders(&$mid)
  1241.     {
  1242.         unset($this->rawHeaders[$mid]);
  1243.         unset($this->header[$mid]);
  1244.         return;
  1245.     }
  1246.     // }}}
  1247.  
  1248.     // {{{ convertBytes()
  1249.     /**
  1250.     * Converts an integer containing the number of bytes in a file to one of Bytes, Kilobytes,
  1251.     * Megabytes, or Gigabytes, appending the unit of measurement.
  1252.     *
  1253.     * @param    int     $bytes 
  1254.     * @return   string 
  1255.     * @access   public
  1256.     */
  1257.     function convertBytes($bytes)
  1258.     {
  1259.         switch (TRUE{
  1260.             case ($bytes pow(2,10)):                             return $bytes." Bytes";
  1261.             case ($bytes >= pow(2,10&& $bytes pow(2,20)):      return round($bytes pow(2,10)0)." KB";
  1262.             case ($bytes >= pow(2,20&& $bytes pow(2,30)):      return round($bytes pow(2,20)1)." MB";
  1263.             case ($bytes pow(2,30)):                             return round($bytes pow(2,30)2)." GB";
  1264.         }
  1265.     }
  1266.     // }}}
  1267.  
  1268.     // {{{ delete()
  1269.     /**
  1270.     * Wrapper function for {@link imap_delete}.  Sets the marked for deletion flag.  Note: POP3
  1271.     * mailboxes do not remember flag settings between connections, for POP3 mailboxes
  1272.     * this function should be used in addtion to {@link expunge}.
  1273.     *
  1274.     * @param    int     &$mid   message id
  1275.     * @return   TRUE|PEAR_Error
  1276.     * @access   public
  1277.     * @see      imap_delete
  1278.     * @see      expunge
  1279.     */
  1280.     function delete(&$mid)
  1281.     {
  1282.         return (imap_delete($this->mailbox$mid))? TRUE : PEAR::raiseError('Unable to mark message: '.$mid.' for deletion.');
  1283.     }
  1284.     // }}}
  1285.  
  1286.     // {{{ expunge()
  1287.     /**
  1288.     * Wrapper function for {@link imap_expunge}.  Expunges messages marked for deletion.
  1289.     *
  1290.     * @param    int     $mid   message id
  1291.     * @return   TRUE|PEAR_Error
  1292.     * @access   public
  1293.     * @see      imap_expunge
  1294.     * @see      delete
  1295.     */
  1296.     function expunge()
  1297.     {
  1298.         return (imap_expunge($this->mailbox))? TRUE : PEAR::raiseError('Unable to expunge mailbox.');
  1299.     }
  1300.     // }}}
  1301.  
  1302.     // {{{ errors()
  1303.     /**
  1304.     * Wrapper function for {@link imap_errors}.  Implodes the array returned by imap_errors,
  1305.     * (if any) and returns the error text.
  1306.     *
  1307.     * @param    string    $seperator     Characters to seperate each error message. '<br />\n' by default.
  1308.     * @return   string|FALSE
  1309.     * @access   public
  1310.     * @see      imap_errors
  1311.     * @see      alerts
  1312.     */
  1313.     function errors($seperator '<br />\n')
  1314.     {
  1315.         $errors = imap_errors();
  1316.         return (is_array($errors&& !empty($errors))implode($seperator$errors: FALSE;
  1317.     }
  1318.     // }}}
  1319.  
  1320.     // {{{ alerts()
  1321.     /**
  1322.     * Wrapper function for {@link imap_alerts}.  Implodes the array returned by imap_alerts,
  1323.     * (if any) and returns the text.
  1324.     *
  1325.     * @param    string    $seperator     Characters to seperate each alert message. '<br />\n' by default.
  1326.     * @return   string|FALSE
  1327.     * @access   public
  1328.     * @see      imap_alerts
  1329.     * @see      errors
  1330.     */
  1331.     function alerts($seperator '<br />\n')
  1332.     {
  1333.         $alerts = imap_alerts();
  1334.         return (is_array($alerts&& !empty($alerts))implode($seperator$alerts: FALSE;
  1335.     }
  1336.     // }}}
  1337.  
  1338.     // {{{ getQuota()
  1339.     /**
  1340.     * Retreives information about the current mailbox's quota.  Rounds up quota sizes and
  1341.     * appends the unit of measurment.  Returns information in a multi-dimensional associative
  1342.     * array.
  1343.     *
  1344.     * @param    string   $folder    Folder to retrieve quota for.
  1345.     * @return   array|PEAR_Error
  1346.     * @throws   Quota not available on this server.  Remedy: none.
  1347.     * @access   public
  1348.     * @see      imap_get_quotaroot
  1349.     */
  1350.     function getQuota($folder 'INBOX')
  1351.     {
  1352.         $quota @imap_get_quotaroot($this->mailbox$folder);
  1353.  
  1354.         // STORAGE Values are returned in KB
  1355.         // Convert back to bytes first
  1356.         // Then round these to the simpliest unit of measurement
  1357.         $rtn['STORAGE']['usage'Mail_IMAP::convertBytes($quota['STORAGE']['usage'* 1024);
  1358.         $rtn['STORAGE']['limit'Mail_IMAP::convertBytes($quota['STORAGE']['limit'* 1024);
  1359.  
  1360.         $rtn['MESSAGE']['usage'Mail_IMAP::convertBytes($quota['MESSAGE']['usage']);
  1361.         $rtn['MESSAGE']['limit'Mail_IMAP::convertBytes($quota['MESSAGE']['limit']);
  1362.  
  1363.         return (empty($quota['STORAGE']['usage']&& empty($quota['STORAGE']['limit']))? PEAR::raiseError('Error: Quota not available for this server.'$rtn;
  1364.     }
  1365.     // }}}
  1366.  
  1367.     // {{{ setFlags()
  1368.     /**
  1369.     * Wrapper function for {@link imap_setflag_full}.  Sets various message flags.
  1370.     * Accepts an array of message ids and an array of flags to be set.
  1371.     *
  1372.     * The flags which you can set are "\\Seen", "\\Answered", "\\Flagged",
  1373.     * "\\Deleted", and "\\Draft" (as defined by RFC2060).
  1374.     *
  1375.     * Warning: POP3 mailboxes do not remember flag settings from connection to connection.
  1376.     *
  1377.     * @param    array  $mids        Array of message ids to set flags on.
  1378.     * @param    array  $flags       Array of flags to set on messages.
  1379.     * @param    int    $action      Flag operation toggle one of MAIL_IMAP_SET_FLAGS (default) or
  1380.     *                                MAIL_IMAP_CLEAR_FLAGS.
  1381.     * @param    int    $options 
  1382.     *     (optional) sets the forth argument of {@link imap_setflag_full} or {@imap_clearflag_full}. 
  1383.     *
  1384.     * @return   BOOL|PEAR_Error
  1385.     * @throws   Message IDs and Flags are to be supplied as arrays.  Remedy: place message ids
  1386.     *            and flags in arrays.
  1387.     * @access   public
  1388.     * @see      imap_setflag_full
  1389.     * @see      imap_clearflag_full
  1390.     */
  1391.     function setFlags($mids$flags$action = 3$options = NULL)
  1392.     {
  1393.         if (is_array($mids&& is_array($flags)) {
  1394.             if ($action == MAIL_IMAP_SET_FLAGS{
  1395.                 return ($options == NULL)? imap_setflag_full($this->mailboximplode(','$mids)implode(' '$flags)) : imap_setflag_full($this->mailboximplode(','$mids)implode(' '$flags)$options);
  1396.             else {
  1397.                 return ($options == NULL)? imap_clearflag_full($this->mailboximplode(','$mids)implode(' '$flags)) : imap_clearflag_full($this->mailboximplode(','$mids)implode(' '$flags)$options);
  1398.                }
  1399.         else {
  1400.             return PEAR::raiseError('Message IDs and Flags are to be supplied as arrays.');
  1401.         }
  1402.     }
  1403.     // }}}
  1404. }
  1405. // }}}
  1406. ?>

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