commiting uncommited changes on live site
[weblabels.fsf.org.git] / crm.fsf.org / 20131203 / files / sites / all / modules-old / civicrm / packages / ezc / Mail / src / parser / parts / multipart_parser.php
1 <?php
2 /**
3 * File containing the ezcMailMultipartParser class
4 *
5 * @package Mail
6 * @version 1.7beta1
7 * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
8 * @license http://ez.no/licenses/new_bsd New BSD License
9 */
10
11 /**
12 * Base class for Multipart parsers.
13 *
14 * @package Mail
15 * @version 1.7beta1
16 * @access private
17 */
18 abstract class ezcMailMultipartParser extends ezcMailPartParser
19 {
20 /**
21 * The boundary separator string.
22 *
23 * @var string
24 */
25 private $boundary = null;
26
27 /**
28 * The headers for the multipart.
29 *
30 * @var ezcMailHeadersHolder
31 */
32 protected $headers = null;
33
34 /**
35 * The headers for the current subpart.
36 *
37 * @var ezcMailHeadersHolder
38 */
39 private $currentPartHeaders = null;
40
41 /**
42 * The current part.
43 *
44 * @var ezcMailPartParser
45 */
46 private $currentPartParser = null;
47
48 /**
49 * This state is used prior to hitting the first part.
50 */
51 const PARSE_STATE_PRE_FIRST = 1;
52
53 /**
54 * This state is used when the parser is parsing headers.
55 */
56 const PARSE_STATE_HEADERS = 2;
57
58 /**
59 * This state is used when the parser is parsing the body.
60 */
61 const PARSE_STATE_BODY = 3;
62
63 /**
64 * This state is set after the last of the parts is closed.
65 */
66 const PARSE_STATE_POST_LAST = 4;
67
68 /**
69 * Stores the state of the parser.
70 *
71 * @var int
72 */
73 private $parserState = self::PARSE_STATE_PRE_FIRST;
74
75 /**
76 * Constructs a new Multipart parser.
77 *
78 * @param ezcMailHeadersHolder $headers
79 */
80 public function __construct( ezcMailHeadersHolder $headers )
81 {
82 $this->headers = $headers;
83
84 // get the boundary
85 preg_match( '/\s*boundary="?([^;"]*);?/i',
86 $this->headers['Content-Type'],
87 $parameters );
88 if ( count( $parameters ) > 0 )
89 {
90 $this->boundary = trim( $parameters[1], '"' );
91 }
92 else
93 {
94 // no boundary?!? Houston, we have a problem.
95 // todo: try to detect the boundary by scanning for --lines
96 }
97 }
98
99 /**
100 * Parses a multipart body.
101 *
102 * @throws ezcBaseFileNotFoundException
103 * if a neccessary temporary file could not be opened.
104 * @param string $origLine
105 */
106 public function parseBody( $origLine )
107 {
108 if ( $this->parserState == self::PARSE_STATE_POST_LAST )
109 {
110 return;
111 }
112
113 $line = rtrim( $origLine, "\r\n" );
114
115 // check if we hit any of the boundaries
116 $newPart = false;
117 $endOfMultipart = false;
118 if ( strlen( $line ) > 0 && $line[0] == "-" )
119 {
120 if ( strcmp( trim( $line ), '--' . $this->boundary ) === 0 )
121 {
122 $newPart = true;
123 }
124 else if ( strcmp( trim( $line ), '--' . $this->boundary . '--' ) === 0 )
125 {
126 $endOfMultipart = true;
127 }
128 }
129
130 // actions to do when starting or finishing a part
131 if ( $newPart || $endOfMultipart )
132 {
133 if ( $this->parserState != self::PARSE_STATE_BODY )
134 {
135 // something is b0rked, we got a new separator before getting a body
136 // we'll skip this part and continue to the next
137 $this->currentPartParser = null;
138 $this->currentPartHeaders = new ezcMailHeadersHolder();
139 $this->parserState = $newPart ? self::PARSE_STATE_HEADERS : self::PARSE_STATE_POST_LAST;
140 }
141 else
142 {
143 // complete the work on the current part if there was any
144 if ( $this->currentPartParser !== null )
145 {
146 $part = $this->currentPartParser->finish();
147 if ( $part !== null ) // parsing failed
148 {
149 $this->partDone( $part );
150 }
151 }
152
153 // prepare for a new part if any
154 $this->currentPartParser = null;
155 $this->parserState =self::PARSE_STATE_POST_LAST;
156 if ( $newPart )
157 {
158 $this->parserState = self::PARSE_STATE_HEADERS;
159 $this->currentPartHeaders = new ezcMailHeadersHolder();
160 }
161 }
162 }
163 // normal data, pass to headers or current body
164 else
165 {
166 if ( $this->parserState == self::PARSE_STATE_HEADERS && $line == '' )
167 {
168 $this->currentPartParser = self::createPartParserForHeaders( $this->currentPartHeaders );
169 $this->parserState = self::PARSE_STATE_BODY;
170 }
171 else if ( $this->parserState == self::PARSE_STATE_HEADERS )
172 {
173 $this->parseHeader( $line, $this->currentPartHeaders );
174 }
175 else if ( $this->parserState == self::PARSE_STATE_BODY )
176 {
177 if ( $this->currentPartParser ) // we may have none if the part type was unknown
178 {
179 // send body data to the part
180 $this->currentPartParser->parseBody( $origLine );
181 }
182 }
183 // we are done parsing the multipart, ignore anything else pushed to us.
184 }
185 }
186
187 /**
188 * Completes the parsing of the multipart and returns the corresponding part.
189 *
190 * This method should not be overriden. Use finishMultipart() instead.
191 *
192 * @return ezcMailMultipart
193 */
194 public function finish()
195 {
196 if ( $this->parserState != self::PARSE_STATE_POST_LAST )
197 {
198 // this should never happen
199 // let's give the last parser a chance to clean up after himself
200 if ( $this->currentPartParser !== null )
201 {
202 $part = $this->currentPartParser->finish();
203 $this->partDone( $part );
204 $this->currentPartParser = null;
205 }
206 }
207 $multipart = $this->finishMultipart();
208 ezcMailPartParser::parsePartHeaders( $this->headers, $multipart );
209 $multipart->boundary = $this->boundary;
210 return $multipart;
211 }
212
213 /**
214 * This function will be called every time a part has been parsed.
215 *
216 * Implementors should put the part into the correct multitype part.
217 * @param ezcMailPart $part
218 */
219 abstract public function partDone( ezcMailPart $part );
220
221 /**
222 * Returns the multipart part corresponding to the parsed object.
223 *
224 * This method is called by finish() when all parts have been parsed.
225 *
226 * @return ezcMailMultipart
227 */
228 abstract public function finishMultipart();
229 }
230 ?>