11<?php
22/*
33* File: Folder.php
4- * Category: Helper
4+ * Category: -
55* Author: M. Goldenbaum
66* Created: 19.01.17 22:21
77* Updated: -
1111*/
1212
1313namespace Webklex \IMAP ;
14+ use Webklex \IMAP \Exceptions \GetMessagesFailedException ;
15+ use Webklex \IMAP \Exceptions \MessageSearchValidationException ;
1416
1517/**
1618 * Class Folder
@@ -141,15 +143,176 @@ public function setChildren($children = []) {
141143 }
142144
143145 /**
144- * Get messages.
146+ * Get a specific message by UID
147+ *
148+ * @param integer $uid Please note that the uid is not unique and can change
149+ * @param integer|null $msglist
150+ *
151+ * @return Message|null
152+ */
153+ public function getMessage ($ uid , $ msglist = null ){
154+ if (imap_msgno ($ this ->getClient ()->getConnection (), $ uid ) > 0 ){
155+ return new Message ($ uid , $ msglist , $ this ->getClient ());
156+ }
157+
158+ return null ;
159+ }
160+
161+ /**
162+ * Get all messages
163+ *
164+ * @param string $criteria
165+ * @param null $fetch_options
166+ * @param bool $parse_body
167+ *
168+ * @return MessageCollection
169+ * @throws GetMessagesFailedException
170+ * @throws MessageSearchValidationException
171+ */
172+ public function getMessages ($ criteria = 'ALL ' , $ fetch_options = null , $ parse_body = true ) {
173+ return $ this ->searchMessages ([[$ criteria ]], $ fetch_options , $ parse_body );
174+ }
175+
176+ /**
177+ * Get all unseen messages
145178 *
146179 * @param string $criteria
147- * @param null $fetch_options
180+ * @param null $fetch_options
181+ * @param bool $parse_body
182+ *
183+ * @return MessageCollection
184+ * @throws GetMessagesFailedException
185+ * @throws MessageSearchValidationException
186+ */
187+ public function getUnseenMessages ($ criteria = 'UNSEEN ' , $ fetch_options = null , $ parse_body = true ) {
188+ return $ this ->searchMessages ([[$ criteria ]], $ fetch_options , $ parse_body );
189+ }
190+
191+ /**
192+ * Search messages by a given search criteria
193+ *
194+ * @param array $where Is a two dimensional array where each array represents a criteria set:
195+ * ---------------------------------------------------------------------------------------
196+ * The following sample would search for all messages received from [email protected] or 197+ * contain the text "Hello world!":
198+ * [['FROM' => '[email protected] '],[' TEXT' => 'Hello world!']] 199+ * ---------------------------------------------------------------------------------------
200+ * The following sample would search for all messages received since march 15 2018:
201+ * [['SINCE' => Carbon::parse('15.03.2018')->format('d M y')]]
202+ * ---------------------------------------------------------------------------------------
203+ * The following sample would search for all flagged messages:
204+ * [['FLAGGED']]
205+ * ---------------------------------------------------------------------------------------
206+ * @param Folder $folder
207+ * @param null $fetch_options
208+ * @param boolean $parse_body
209+ * @param string $charset
210+ *
211+ * @return MessageCollection
212+ * @throws GetMessagesFailedException
213+ * @throws MessageSearchValidationException
214+ *
215+ * @doc http://php.net/manual/en/function.imap-search.php
216+ * imap_search() only supports IMAP2 search criterias, because the function mail_criteria() (from c-client lib)
217+ * is used in ext/imap/php_imap.c for parsing the search string.
218+ * IMAP2 search criteria is defined in RFC 1176, section "tag SEARCH search_criteria".
219+ *
220+ * https://tools.ietf.org/html/rfc1176 - INTERACTIVE MAIL ACCESS PROTOCOL - VERSION 2
221+ * https://tools.ietf.org/html/rfc1064 - INTERACTIVE MAIL ACCESS PROTOCOL - VERSION 2
222+ * https://tools.ietf.org/html/rfc822 - STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES
223+ * Date and time example from RFC822:
224+ * date-time = [ day "," ] date time ; dd mm yy
225+ * ; hh:mm:ss zzz
226+ *
227+ * day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
228+ *
229+ * date = 1*2DIGIT month 2DIGIT ; day month year
230+ * ; e.g. 20 Jun 82
231+ *
232+ * month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
148233 *
149- * @return \Illuminate\Support\Collection
234+ * time = hour zone ; ANSI and Military
235+ *
236+ * hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
237+ *
238+ * zone = "UT" / "GMT" ; Universal Time
239+ * ; North American : UT
240+ * = "EST" / "EDT" ; Eastern: - 5/ - 4
241+ * = "CST" / "CDT" ; Central: - 6/ - 5
242+ * = "MST" / "MDT" ; Mountain: - 7/ - 6
243+ * = "PST" / "PDT" ; Pacific: - 8/ - 7
244+ * = 1ALPHA ; Military: Z = UT;
245+ * ; A:-1; (J not used)
246+ * ; M:-12; N:+1; Y:+12
247+ * / ( ("+" / "-") 4DIGIT ) ; Local differential
248+ * ; hours+min. (HHMM)
249+ *
250+ */
251+ public function searchMessages (array $ where , $ fetch_options = null , $ parse_body = true , $ charset = "UTF-8 " ) {
252+
253+ $ this ->getClient ()->checkConnection ();
254+
255+ if ($ this ->validateWhereStatements ($ where )){
256+ throw new MessageSearchValidationException ('Invalid imap search criteria provided ' );
257+ }
258+
259+ try {
260+ $ this ->getClient ()->openFolder ($ this );
261+ $ messages = MessageCollection::make ([]);
262+
263+ $ query = '' ;
264+ foreach ($ where as $ statement ){
265+ if (count ($ statement ) == 1 ){
266+ $ query .= $ statement [0 ];
267+ }else {
268+ $ query .= $ statement [0 ].' " ' .$ statement [1 ].'" ' ;
269+ }
270+ }
271+
272+ $ availableMessages = imap_search ($ this ->getClient ()->getConnection (), $ query , SE_UID , $ charset );
273+
274+ if ($ availableMessages !== false ) {
275+ $ msglist = 1 ;
276+ foreach ($ availableMessages as $ msgno ) {
277+ $ message = new Message ($ msgno , $ msglist , $ this ->getClient (), $ fetch_options , $ parse_body );
278+
279+ $ messages ->put ($ message ->getMessageId (), $ message );
280+ $ msglist ++;
281+ }
282+ }
283+
284+ return $ messages ;
285+ } catch (\Exception $ e ) {
286+ $ message = $ e ->getMessage ();
287+
288+ throw new GetMessagesFailedException ($ message );
289+ }
290+ }
291+
292+ /**
293+ * Validate a given statement array
294+ *
295+ * @param array $statements
296+ *
297+ * @return bool
298+ *
299+ * @doc http://php.net/manual/en/function.imap-search.php
300+ * https://tools.ietf.org/html/rfc1064
301+ * https://tools.ietf.org/html/rfc822
150302 */
151- public function getMessages ($ criteria = 'ALL ' , $ fetch_options = null ) {
152- return collect ($ this ->client ->getMessages ($ this , $ criteria , $ fetch_options ));
303+ protected function validateWhereStatements ($ statements ){
304+ foreach ($ statements as $ statement ){
305+ $ criteria = $ statement [0 ];
306+ if (in_array (explode ($ criteria , ' ' ), [
307+ 'OR ' , 'AND ' ,
308+ 'ALL ' , 'ANSWERED ' , 'BCC ' , 'BEFORE ' , 'BODY ' , 'CC ' , 'DELETED ' , 'FLAGGED ' , 'FROM ' , 'KEYWORD ' ,
309+ 'NEW ' , 'OLD ' , 'ON ' , 'RECENT ' , 'SEEN ' , 'SINCE ' , 'SUBJECT ' , 'TEXT ' , 'TO ' ,
310+ 'UNANSWERED ' , 'UNDELETED ' , 'UNFLAGGED ' , 'UNKEYWORD ' , 'UNSEEN ' ]) == false ){
311+ return false ;
312+ }
313+ }
314+
315+ return empty ($ statements ) == false ;
153316 }
154317
155318 /**
@@ -247,4 +410,13 @@ public function getStatus($options){
247410 public function appendMessage ($ message , $ options = null , $ internal_date = null ){
248411 return imap_append ($ this ->client ->connection , $ this ->path , $ message , $ options , $ internal_date );
249412 }
413+
414+ /**
415+ * Get the current Client instance
416+ *
417+ * @return Client
418+ */
419+ public function getClient (){
420+ return $ this ->client ;
421+ }
250422}
0 commit comments