/Mail/src/transports/mbox/mbox_transport.php

https://github.com/F5/zetacomponents · PHP · 211 lines · 97 code · 10 blank · 104 comment · 14 complexity · c9b8b1045e4c21fdb6e1492ef7b885d3 MD5 · raw file

  1. <?php
  2. /**
  3. * File containing the ezcMailMboxTransport class
  4. *
  5. * Licensed to the Apache Software Foundation (ASF) under one
  6. * or more contributor license agreements. See the NOTICE file
  7. * distributed with this work for additional information
  8. * regarding copyright ownership. The ASF licenses this file
  9. * to you under the Apache License, Version 2.0 (the
  10. * "License"); you may not use this file except in compliance
  11. * with the License. You may obtain a copy of the License at
  12. *
  13. * http://www.apache.org/licenses/LICENSE-2.0
  14. *
  15. * Unless required by applicable law or agreed to in writing,
  16. * software distributed under the License is distributed on an
  17. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  18. * KIND, either express or implied. See the License for the
  19. * specific language governing permissions and limitations
  20. * under the License.
  21. *
  22. * @package Mail
  23. * @version //autogen//
  24. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
  25. */
  26. /**
  27. * ezcMailMboxTransport implements mail retrieval from an mbox file.
  28. *
  29. * The mbox set is constructed from a file pointer and iterates over all the
  30. * messages in an mbox file.
  31. *
  32. * @package Mail
  33. * @version //autogen//
  34. * @mainclass
  35. */
  36. class ezcMailMboxTransport
  37. {
  38. /**
  39. * Holds the filepointer to the mbox
  40. *
  41. * @var resource(filepointer)
  42. */
  43. public $fh;
  44. /**
  45. * Constructs the ezcMailMboxTransport object
  46. *
  47. * Opens the mbox $fileName.
  48. *
  49. * @throws ezcBaseFileNotFoundException
  50. * if the mbox file could not be found.
  51. * @throws ezcBaseFilePermissionException
  52. * if the mbox file could be opened for reading.
  53. * @param string $fileName
  54. */
  55. public function __construct( $fileName )
  56. {
  57. if ( !file_exists( $fileName ) )
  58. {
  59. throw new ezcBaseFileNotFoundException( $fileName, 'mbox' );
  60. }
  61. if ( !is_readable( $fileName ) )
  62. {
  63. throw new ezcBaseFilePermissionException( $fileName, ezcBaseFileException::READ );
  64. }
  65. $this->fh = fopen( $fileName, 'rt' );
  66. }
  67. /**
  68. * Finds the position of the first message while skipping a possible header.
  69. *
  70. * Mbox files can contain a header which does not describe an email
  71. * message. This method skips over this optional header by checking for a
  72. * specific From MAILER-DAEMON header.
  73. *
  74. * @return int
  75. */
  76. private function findFirstMessage()
  77. {
  78. $data = fgets( $this->fh );
  79. fseek( $this->fh, 0 );
  80. if ( substr( $data, 0, 18 ) === 'From MAILER-DAEMON' )
  81. {
  82. return $this->findNextMessage();
  83. }
  84. else
  85. {
  86. return 0;
  87. }
  88. }
  89. /**
  90. * Reads through the Mbox file and stops at the next message.
  91. *
  92. * Messages in Mbox files are separated with lines starting with "From "
  93. * and this function reads to the next "From " marker. It then returns the
  94. * current posistion in the file. If EOF is detected during reading the
  95. * function returns false instead.
  96. *
  97. * @return int
  98. */
  99. private function findNextMessage()
  100. {
  101. do
  102. {
  103. $data = fgets( $this->fh );
  104. } while ( !feof( $this->fh ) && substr( $data, 0, 5 ) !== "From " );
  105. if ( feof( $this->fh ) )
  106. {
  107. return false;
  108. }
  109. return ftell( $this->fh );
  110. }
  111. /**
  112. * This function reads through the whole mbox and returns starting positions of the messages.
  113. *
  114. * @return array(int=>int)
  115. */
  116. public function listMessages()
  117. {
  118. $messages = array();
  119. fseek( $this->fh, 0 );
  120. // Skip the first mail as this is the mbox header
  121. $position = $this->findFirstMessage();
  122. if ( $position === false )
  123. {
  124. return $messages;
  125. }
  126. // Continue reading through the rest of the mbox
  127. do
  128. {
  129. $position = $this->findNextMessage();
  130. if ( $position !== false )
  131. {
  132. $messages[] = $position;
  133. }
  134. } while ( $position !== false );
  135. return $messages;
  136. }
  137. /**
  138. * Returns an ezcMailMboxSet containing all the messages in the mbox.
  139. *
  140. * @return ezcMailMboxSet
  141. */
  142. public function fetchAll()
  143. {
  144. $messages = $this->listMessages();
  145. return new ezcMailMboxSet( $this->fh, $messages );
  146. }
  147. /**
  148. * Returns an ezcMailMboxSet containing only the $number -th message in the mbox.
  149. *
  150. * @throws ezcMailNoSuchMessageException
  151. * if the message $number is out of range.
  152. * @param int $number
  153. * @return ezcMailMboxSet
  154. */
  155. public function fetchByMessageNr( $number )
  156. {
  157. $messages = $this->listMessages();
  158. if ( !isset( $messages[$number] ) )
  159. {
  160. throw new ezcMailNoSuchMessageException( $number );
  161. }
  162. return new ezcMailMboxSet( $this->fh, array( 0 => $messages[$number] ) );
  163. }
  164. /**
  165. * Returns an ezcMailMboxSet with $count messages starting from $offset.
  166. *
  167. * Fetches $count messages starting from the $offset and returns them as a
  168. * ezcMailMboxSet. If $count is not specified or if it is 0, it fetches
  169. * all messages starting from the $offset.
  170. *
  171. * @throws ezcMailInvalidLimitException
  172. * if $count is negative.
  173. * @throws ezcMailOffsetOutOfRangeException
  174. * if $offset is outside of the existing range of messages.
  175. * @param int $offset
  176. * @param int $count
  177. * @return ezcMailMboxSet
  178. */
  179. public function fetchFromOffset( $offset, $count = 0 )
  180. {
  181. if ( $count < 0 )
  182. {
  183. throw new ezcMailInvalidLimitException( $offset, $count );
  184. }
  185. $messages = $this->listMessages();
  186. if ( !isset( $messages[$offset] ) )
  187. {
  188. throw new ezcMailOffsetOutOfRangeException( $offset, $count );
  189. }
  190. if ( $count == 0 )
  191. {
  192. $range = array_slice( $messages, $offset );
  193. }
  194. else
  195. {
  196. $range = array_slice( $messages, $offset, $count );
  197. }
  198. return new ezcMailMboxSet( $this->fh, $range );
  199. }
  200. }
  201. ?>