diff --git a/CHANGELOG.md b/CHANGELOG.md index b5035414..62ea0d92 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) princip - NaN ### Added -- NaN +- sizes() methods to protocol interface and implmentations (to have FETCH NNN RFC822.SIZE attribute available) ### Breaking changes - NaN diff --git a/examples/size_test.php b/examples/size_test.php new file mode 100644 index 00000000..44f832c5 --- /dev/null +++ b/examples/size_test.php @@ -0,0 +1,83 @@ + 'toFill', + 'port' => 993, + 'encryption' => 'ssl', + 'validate_cert' => true, + 'username' => 'toFill', + 'password' => 'toFill', + 'protocol' => 'imap' +); +set_include_path('/home/didi1357/git/php-imap/src'); + + +ini_set('display_errors', 1); +ini_set('display_startup_errors', 1); +error_reporting(E_ALL); + +require_once 'IMAP.php'; +require_once 'Traits/HasEvents.php'; +require_once 'Exceptions/MaskNotFoundException.php'; +require_once 'Client.php'; +require_once 'ClientManager.php'; +require_once 'Support/Masks/Mask.php'; +require_once 'Support/Masks/MessageMask.php'; +require_once 'Support/Masks/AttachmentMask.php'; +require_once 'Connection/Protocols/Response.php'; +require_once 'Connection/Protocols/ProtocolInterface.php'; +require_once 'Connection/Protocols/Protocol.php'; +require_once 'Connection/Protocols/ImapProtocol.php'; +require_once '../tests/vendor/autoload.php'; +require_once 'Support/PaginatedCollection.php'; +require_once 'Support/FolderCollection.php'; +require_once 'Folder.php'; +require_once 'Exceptions/ResponseException.php'; +require_once 'Query/Query.php'; +require_once 'Query/WhereQuery.php'; +require_once 'Support/MessageCollection.php'; +require_once 'Support/FlagCollection.php'; +require_once 'Support/AttachmentCollection.php'; +require_once 'Part.php'; +require_once 'Structure.php'; +require_once 'Attribute.php'; +require_once 'Address.php'; +require_once 'EncodingAliases.php'; +require_once 'Header.php'; +require_once 'Message.php'; + +use Webklex\PHPIMAP\ClientManager; +use Webklex\PHPIMAP\Support\Masks\MessageMask; +use Webklex\PHPIMAP\Support\Masks\AttachmentMask; + +$CONFIG['masks'] = array( + 'message' => MessageMask::class, + 'attachment' => AttachmentMask::class +); +echo "
";
+$cm = new ClientManager($options = []);
+$client = $cm->make($CONFIG)->connect();
+//$client->getConnection()->enableDebug(); // uncomment this for debug output!
+$folder = $client->getFolderByPath('INBOX');
+//$message = $folder->messages()->getMessageByMsgn(1); // did not work as msgn implementation is currently broken!
+$message = $folder->messages()->getMessageByUid(2);
+var_dump($message->getSize());
+
+
+?>
+
diff --git a/src/Connection/Protocols/ImapProtocol.php b/src/Connection/Protocols/ImapProtocol.php
index fc23c56f..07ea3f6d 100644
--- a/src/Connection/Protocols/ImapProtocol.php
+++ b/src/Connection/Protocols/ImapProtocol.php
@@ -698,7 +698,7 @@ public function fetch(array|string $items, array|int $from, mixed $to = null, in
             // if we want only one message we can ignore everything else and just return
             if ($to === null && !is_array($from) && ($uid === IMAP::ST_UID ? $tokens[2][$uidKey] == $from : $tokens[0] == $from)) {
                 // we still need to read all lines
-                while (!$this->readLine($response, $tokens, $tag))
+                if (!$this->readLine($response, $tokens, $tag))
                     return $response->setResult($data);
             }
             if ($uid === IMAP::ST_UID) {
@@ -756,6 +756,19 @@ public function flags(int|array $uids, int|string $uid = IMAP::ST_UID): Response
         return $this->fetch(["FLAGS"], $uids, null, $uid);
     }
 
+    /**
+     * Fetch message sizes
+     * @param int|array $uids
+     * @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
+     * message numbers instead.
+     *
+     * @return Response
+     * @throws RuntimeException
+     */
+    public function sizes(int|array $uids, int|string $uid = IMAP::ST_UID): Response {
+        return $this->fetch(["RFC822.SIZE"], $uids, null, $uid);
+    }
+
     /**
      * Get uid for a given id
      * @param int|null $id message number
diff --git a/src/Connection/Protocols/LegacyProtocol.php b/src/Connection/Protocols/LegacyProtocol.php
index b515d255..65c5342d 100644
--- a/src/Connection/Protocols/LegacyProtocol.php
+++ b/src/Connection/Protocols/LegacyProtocol.php
@@ -314,6 +314,34 @@ public function flags(int|array $uids, int|string $uid = IMAP::ST_UID): Response
             return $result;
         });
     }
+    
+    /**
+     * Fetch message sizes
+     * @param int|array $uids
+     * @param int|string $uid set to IMAP::ST_UID if you pass message unique identifiers instead of numbers.
+     *
+     * @return Response
+     */
+    public function sizes(int|array $uids, int|string $uid = IMAP::ST_UID): Response {
+        return $this->response()->wrap(function($response)use($uids, $uid){
+            /** @var Response $response */
+            $result = [];
+            $uids = is_array($uids) ? $uids : [$uids];
+            $uid_text = implode("','",$uids);
+            $response->addCommand("imap_fetch_overview");
+            $raw_overview = false;
+            if ($uid == IMAP::ST_UID)
+              $raw_overview = imap_fetch_overview($this->stream, $uid_text, FT_UID);
+            else
+              $raw_overview = imap_fetch_overview($this->stream, $uid_text);
+            if ($raw_overview !== false) {
+              foreach ($raw_overview as $overview_element) {
+                $result[$overview_element[$uid == IMAP::ST_UID ? 'uid': 'msgno']] = $overview_element['size'];
+              }
+            }
+            return $result;
+        });
+    }
 
     /**
      * Get uid for a given id
diff --git a/src/Connection/Protocols/ProtocolInterface.php b/src/Connection/Protocols/ProtocolInterface.php
index 0093e513..c02d7800 100644
--- a/src/Connection/Protocols/ProtocolInterface.php
+++ b/src/Connection/Protocols/ProtocolInterface.php
@@ -151,6 +151,17 @@ public function headers(int|array $uids, string $rfc = "RFC822", int|string $uid
      * @throws RuntimeException
      */
     public function flags(int|array $uids, int|string $uid = IMAP::ST_UID): Response;
+    
+    /**
+     * Fetch message sizes
+     * @param int|array $uids
+     * @param int|string $uid set to IMAP::ST_UID or any string representing the UID - set to IMAP::ST_MSGN to use
+     * message numbers instead.
+     *
+     * @return Response
+     * @throws RuntimeException
+     */
+    public function sizes(int|array $uids, int|string $uid = IMAP::ST_UID): Response;
 
     /**
      * Get uid for a given id
diff --git a/src/Exceptions/MessageSizeFetchingException.php b/src/Exceptions/MessageSizeFetchingException.php
new file mode 100644
index 00000000..f14fce51
--- /dev/null
+++ b/src/Exceptions/MessageSizeFetchingException.php
@@ -0,0 +1,24 @@
+attributes[$name] = $this->client->getConnection()->getMessageNumber($this->uid)->validate()->integer();
                 return $this->attributes[$name];
+            case "size":
+                if (!isset($this->attributes[$name])) {
+                    $this->fetchSize();
+                }
+                return $this->attributes[$name];
         }
 
         return $this->header->get($name);
@@ -592,6 +597,20 @@ public function parseBody(): Message {
 
         return $body;
     }
+    
+    /**
+     * Fetches the size for this message.
+     * 
+     * @throws MessageSizeFetchingException
+     */
+    private function fetchSize(): void {
+        $sequence_id = $this->getSequenceId();
+        $sizes = $this->client->getConnection()->sizes([$sequence_id], $this->sequence)->validatedData();
+         if (!isset($sizes[$sequence_id])) {
+            throw new MessageSizeFetchingException("sizes did not set an array entry for the supplied sequence_id", 0);
+        }
+        $this->attributes["size"] = $sizes[$sequence_id];
+    }
 
     /**
      * Handle auto "Seen" flag handling
@@ -1301,6 +1320,15 @@ public function getHeader(): ?Header {
         return $this->header;
     }
 
+    /**
+     * Get the message size in bytes
+     *
+     * @return int Size of the message in bytes
+     */
+    public function getSize(): int {
+        return $this->get("size");
+    }
+
     /**
      * Get the current client
      *
@@ -1565,7 +1593,7 @@ public function getSequence(): int {
     }
 
     /**
-     * Set the sequence type
+     * Get the current sequence id (either a UID or a message number!)
      *
      * @return int
      */