| <?php |
| /** |
| * File containing the ezcMailPartParser class |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * @package Mail |
| * @version //autogen// |
| * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
| */ |
| |
| /** |
| * Base class for all parser parts. |
| * |
| * Parse process |
| * 1. Figure out the headers of the next part. |
| * 2. Based on the headers, create the parser for the bodyPart corresponding to |
| * the headers. |
| * 3. Parse the body line by line. In the case of a multipart or a digest recursively |
| * start this process. Note that in the case of RFC822 messages the body contains |
| * headers. |
| * 4. call finish() on the partParser and retrieve the ezcMailPart |
| * |
| * Each parser part gets the header for that part through the constructor |
| * and is responsible for parsing the body of that part. |
| * Parsing of the body is done on a push basis trough the parseBody() method |
| * which is called repeatedly by the parent part for each line in the message. |
| * |
| * When there are no more lines the parent part will call finish() and the mail |
| * part corresponding to the part you are parsing should be returned. |
| * |
| * @todo case on headers |
| * @package Mail |
| * @version //autogen// |
| * @access private |
| */ |
| abstract class ezcMailPartParser |
| { |
| /** |
| * Mail headers which can appear maximum one time in a mail message, |
| * as defined by RFC 2822. |
| * |
| * @var array(string) |
| */ |
| protected static $uniqueHeaders = array( 'bcc', 'cc', 'content-type', |
| 'content-disposition', 'from', |
| 'content-transfer-encoding', |
| 'return-path', |
| 'in-reply-to', 'references', |
| 'message-id', 'date', 'reply-to', |
| 'sender', 'subject', 'sender', 'to' ); |
| |
| /** |
| * The default is to parse text attachments into ezcMailTextPart objects. |
| * |
| * Setting this to true before calling the parser will parse text attachments |
| * into ezcMailFile objects. Use the parser options for this: |
| * |
| * <code> |
| * $parser = new ezcMailParser(); |
| * $parser->options->parseTextAttachmentsAsFiles = true; |
| * // call $parser->parseMail( $set ); |
| * </code> |
| * |
| * @var bool |
| */ |
| public static $parseTextAttachmentsAsFiles = false; |
| |
| /** |
| * The name of the last header parsed. |
| * |
| * This variable is used when glueing together multi-line headers. |
| * |
| * @var string |
| */ |
| private $lastParsedHeader = null; |
| |
| /** |
| * Parse the body of a message line by line. |
| * |
| * This method is called by the parent part on a push basis. When there |
| * are no more lines the parent part will call finish() to retrieve the |
| * mailPart. |
| * |
| * @param string $line |
| */ |
| abstract public function parseBody( $line ); |
| |
| /** |
| * Return the result of the parsed part. |
| * |
| * This method is called when all the lines of this part have been parsed. |
| * |
| * @return ezcMailPart |
| */ |
| abstract public function finish(); |
| |
| /** |
| * Returns a part parser corresponding to the given $headers. |
| * |
| * @throws ezcBaseFileNotFoundException |
| * if a neccessary temporary file could not be openened. |
| * @param ezcMailHeadersHolder $headers |
| * @return ezcMailPartParser |
| */ |
| static public function createPartParserForHeaders( ezcMailHeadersHolder $headers ) |
| { |
| // default as specified by RFC2045 - #5.2 |
| $mainType = 'text'; |
| $subType = 'plain'; |
| |
| // parse the Content-Type header |
| if ( isset( $headers['Content-Type'] ) ) |
| { |
| $matches = array(); |
| // matches "type/subtype; blahblahblah" |
| preg_match_all( '/^(\S+)\/([^;]+)/', |
| $headers['Content-Type'], $matches, PREG_SET_ORDER ); |
| if ( count( $matches ) > 0 ) |
| { |
| $mainType = strtolower( $matches[0][1] ); |
| $subType = strtolower( $matches[0][2] ); |
| } |
| } |
| $bodyParser = null; |
| |
| // create the correct type parser for this the detected type of part |
| switch ( $mainType ) |
| { |
| /* RFC 2045 defined types */ |
| case 'image': |
| case 'audio': |
| case 'video': |
| case 'application': |
| $bodyParser = new ezcMailFileParser( $mainType, $subType, $headers ); |
| break; |
| |
| case 'message': |
| switch ( $subType ) |
| { |
| case "rfc822": |
| $bodyParser = new ezcMailRfc822DigestParser( $headers ); |
| break; |
| |
| case "delivery-status": |
| $bodyParser = new ezcMailDeliveryStatusParser( $headers ); |
| break; |
| |
| default: |
| $bodyParser = new ezcMailFileParser( $mainType, $subType, $headers ); |
| break; |
| } |
| break; |
| |
| case 'text': |
| if ( ezcMailPartParser::$parseTextAttachmentsAsFiles === true ) |
| { |
| $bodyParser = new ezcMailFileParser( $mainType, $subType, $headers ); |
| } |
| else |
| { |
| $bodyParser = new ezcMailTextParser( $subType, $headers ); |
| } |
| break; |
| |
| case 'multipart': |
| switch ( $subType ) |
| { |
| case 'mixed': |
| $bodyParser = new ezcMailMultipartMixedParser( $headers ); |
| break; |
| case 'alternative': |
| $bodyParser = new ezcMailMultipartAlternativeParser( $headers ); |
| break; |
| case 'related': |
| $bodyParser = new ezcMailMultipartRelatedParser( $headers ); |
| break; |
| case 'digest': |
| $bodyParser = new ezcMailMultipartDigestParser( $headers ); |
| break; |
| case 'report': |
| $bodyParser = new ezcMailMultipartReportParser( $headers ); |
| break; |
| default: |
| $bodyParser = new ezcMailMultipartMixedParser( $headers ); |
| break; |
| } |
| break; |
| |
| /* extensions */ |
| default: |
| // we treat the body as binary if no main content type is set |
| // or if it is unknown |
| $bodyParser = new ezcMailFileParser( $mainType, $subType, $headers ); |
| break; |
| } |
| return $bodyParser; |
| } |
| |
| /** |
| * Parses the header given by $line and adds to $headers. |
| * |
| * This method is usually used to parse the headers for a subpart. The |
| * only exception is RFC822 parts since you know the type in advance. |
| * |
| * @todo deal with headers that are listed several times |
| * @param string $line |
| * @param ezcMailHeadersHolder $headers |
| */ |
| protected function parseHeader( $line, ezcMailHeadersHolder $headers ) |
| { |
| $matches = array(); |
| preg_match_all( "/^([\w-_]*):\s?(.*)/", $line, $matches, PREG_SET_ORDER ); |
| if ( count( $matches ) > 0 ) |
| { |
| if ( !in_array( strtolower( $matches[0][1] ), self::$uniqueHeaders ) ) |
| { |
| $arr = $headers[$matches[0][1]]; |
| $arr[0][] = str_replace( "\t", " ", trim( $matches[0][2] ) ); |
| $headers[$matches[0][1]] = $arr; |
| } |
| else |
| { |
| $headers[$matches[0][1]] = str_replace( "\t", " ", trim( $matches[0][2] ) ); |
| } |
| $this->lastParsedHeader = $matches[0][1]; |
| } |
| else if ( $this->lastParsedHeader !== null ) // take care of folding |
| { |
| if ( !in_array( strtolower( $this->lastParsedHeader ), self::$uniqueHeaders ) ) |
| { |
| $arr = $headers[$this->lastParsedHeader]; |
| $arr[0][count( $arr[0] ) - 1] .= str_replace( "\t", " ", $line ); |
| $headers[$this->lastParsedHeader] = $arr; |
| } |
| else |
| { |
| $headers[$this->lastParsedHeader] .= str_replace( "\t", " ", $line ); |
| } |
| } |
| // else -invalid syntax, this should never happen. |
| } |
| |
| /** |
| * Scans through $headers and sets any specific header properties on $part. |
| * |
| * Currently we only have Content-Disposition on the ezcMailPart level. |
| * All parser parts must call this method once. |
| * |
| * @param ezcMailHeadersHolder $headers |
| * @param ezcMailPart $part |
| */ |
| static public function parsePartHeaders( ezcMailHeadersHolder $headers, ezcMailPart $part ) |
| { |
| if ( isset( $headers['Content-Disposition'] ) ) |
| { |
| $part->contentDisposition = ezcMailRfc2231Implementation::parseContentDisposition( $headers['Content-Disposition'] ); |
| } |
| } |
| } |
| |
| ?> |