Flourish PHP Unframework
This is an archived copy of the forum for reference purposes

mailbox - ListMessages in reverse order?

posted by gexus 9 years ago

Hello,

I'm just starting to use the fMailbox and was wondering if it's possible to retrieve the list in reverse order? So the newest items would be at the top of the array.. I'm using array_reverse() which is actually working just fine, just wanted to see if there's a better option.

Thanks!

That sounds like a reasonable feature to add. If you open a ticket, it will get added to my list of things to do.

posted by wbond 9 years ago

Hi there

This should be all that's required to change the function to allow for newest first (which I've set to be the default on my copy as it makes sense to me).

I basically just added an extra parameter and in the imap and POP3 sections did the start and finish based on the order parameter, and there's an arsort at the end to reverse the order of the array if we're sorting by newest.

	public function listMessages($limit=NULL, $page=NULL, $order='newest')
	{
		$this->connect();
		
		if ($this->type == 'imap') {
			$total_messages = 0;
			$response = $this->write('STATUS "INBOX" (MESSAGES)');
			foreach ($response as $line) {
				if (preg_match('#^\\s*\\*\\s+STATUS\\s+"?INBOX"?\\s+\\((.*)\\)$#', $line, $match)) {
					$details = self::parseResponse($match[1], TRUE);
					$total_messages = $details['messages'];
				}
			}
			
			if (!$limit) {
				$start = 1;
				$end   = '*';
			} else {
				if (!$page) {
					$page = 1;
				}
				if ($order == 'newest') {
					$start = $total_messages - $limit * $page + 1;
					$end   = $start + $limit - 1;
				} else {
					$start = ($limit * ($page-1)) + 1;
					$end   = $start + $limit - 1;
				}
			}
			
			if ($start > $total_messages) {
				return array();
			}
			
			if ($end > $total_messages) {
				$end = $total_messages;
			}
			
			$output = array();

				$response = $this->write('FETCH ' . $start . ':' . $end . ' (UID INTERNALDATE RFC822.SIZE ENVELOPE)');

			foreach ($response as $line) {
				if (preg_match('#^\\s*\\*\\s+(\\d+)\\s+FETCH\\s+\\((.*)\\)$#', $line, $match)) {
					$details = self::parseResponse($match[2], TRUE);
					$info    = array();
					
					$info['uid']      = $details['uid'];
					$info['received'] = self::cleanDate($details['internaldate']);
					$info['size']     = $details['rfc822.size'];
					
					$envelope = $details['envelope'];
					$info['date']    = $envelope[0] != 'NIL' ? $envelope[0] : '';
					$info['from']    = self::joinEmails($envelope[2]);
					if (preg_match('#=\\?[^\\?]+\\?[QB]\\?[^\\?]+\\?=#', $envelope[1])) {
						do {
							$last_subject = $envelope[1];
							$envelope[1] = preg_replace('#(=\\?([^\\?]+)\\?[QB]\\?[^\\?]+\\?=) (\\s*=\\?\\2)#', '\\1\\3', $envelope[1]);
						} while ($envelope[1] != $last_subject);
						$info['subject'] = self::decodeHeader($envelope[1]);
					} else {
						$info['subject'] = $envelope[1] == 'NIL' ? '' : self::decodeHeader($envelope[1]);
					}
					if ($envelope[9] != 'NIL') {
						$info['message_id'] = $envelope[9];
					}
					if ($envelope[5] != 'NIL') {
						$info['to'] = self::joinEmails($envelope[5]);
					}
					if ($envelope[8] != 'NIL') {
						$info['in_reply_to'] = $envelope[8];
					}
					
					$output[$info['uid']] = $info;
				}
			}
		
		} elseif ($this->type == 'pop3') {
			if (!$limit) {
				$start = 1;
				$end   = NULL;
			} else {
				if (!$page) {
					$page = 1;
				}
				if ($order == 'newest') {
					$start = $total_messages - $limit * $page + 1;
					$end   = $start + $limit - 1;
				} else {
					$start = ($limit * ($page-1)) + 1;
					$end   = $start + $limit - 1;
				}
			}
			
			$total_messages = 0;
			$response = $this->write('STAT', 1);
			preg_match('#^\\+OK\\s+(\\d+)\\s+#', $response[0], $match);
			$total_messages = $match[1];
			
			if ($start > $total_messages) {
				return array();
			}
			
			if ($end === NULL || $end > $total_messages) {
				$end = $total_messages;
			}
			
			$sizes = array();
			$response = $this->write('LIST');
			array_shift($response);
			foreach ($response as $line) {
				preg_match('#^(\\d+)\\s+(\\d+)$#', $line, $match);
				$sizes[$match[1]] = $match[2];
			}
			
			$output = array();
			for ($i = $start; $i <= $end; $i++) {
				$response = $this->write('TOP ' . $i . ' 1');
				array_shift($response);
				$value = array_pop($response);
				// Some servers add an extra blank line after the 1 requested line
				if (trim($value) == '') {
					array_pop($response);
				}
				
				$response = trim(join("\\r\\n", $response));
				$headers = self::parseHeaders($response);
				$output[$i] = array(
					'uid'      => $i,
					'received' => self::cleanDate(preg_replace('#^.*;\\s*([^;]+)$#', '\\1', $headers['received'][0])),
					'size'     => $sizes[$i],
					'date'     => $headers['date'],
					'from'     => self::joinEmails(array($headers['from'])),
					'subject'  => isset($headers['subject']) ? $headers['subject'] : ''
				);
				if (isset($headers['message-id'])) {
					$output[$i]['message_id'] = $headers['message-id'];
				}
				if (isset($headers['to'])) {
					$output[$i]['to'] = self::joinEmails($headers['to']);
				}
				if (isset($headers['in-reply-to'])) {
					$output[$i]['in_reply_to'] = $headers['in-reply-to'];
				}
			}
		}
		if ($order == 'newest') {
			arsort($output);
		}
		return $output;
	}

EDIT: I'm not suggesting it's the best way of doing it, but it seems to be working to me - if anyone wants to use it then just replace the relevant function with my version above and it should be good to go.

(No idea why when I originally posted this I said it wasn't pretty - I meant my bits not the function as a whole which is quite nice ;) ).

posted by pete 8 years ago