Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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