Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 92 additions & 28 deletions src/PhpImap/Mailbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ public function decodeStringFromUtf7ImapToUtf8($str)
public function switchMailbox($imapPath)
{
$this->imapPath = $imapPath;
$this->imap('reopen', $this->imapPath);
$this->imap('reopen', $this->getCombinedPath($imapPath, true));
}

protected function initImapStreamWithRetry()
Expand Down Expand Up @@ -439,7 +439,7 @@ public function checkMailbox()
*/
public function createMailbox($name)
{
$this->imap('createmailbox', $this->imapPath.$this->getPathDelimiter().$name);
$this->imap('createmailbox', $this->getCombinedPath($name));
}

/**
Expand All @@ -449,7 +449,7 @@ public function createMailbox($name)
*/
public function deleteMailbox($name)
{
$this->imap('deletemailbox', $this->imapPath.$this->getPathDelimiter().$name);
$this->imap('deletemailbox', $this->getCombinedPath($name));
}

/**
Expand All @@ -460,7 +460,7 @@ public function deleteMailbox($name)
*/
public function renameMailbox($oldName, $newName)
{
$this->imap('renamemailbox', [$this->imapPath.$this->getPathDelimiter().$oldName, $this->imapPath.$this->getPathDelimiter().$newName]);
$this->imap('renamemailbox', [$this->getCombinedPath($oldName), $this->getCombinedPath($newName)]);
}

/**
Expand Down Expand Up @@ -622,17 +622,19 @@ public function markMailsAsImportant(array $mailId)
/**
* Causes a store to add the specified flag to the flags set for the mails in the specified sequence.
*
* @param string $flag which you can set are \Seen, \Answered, \Flagged, \Deleted, and \Draft as defined by RFC2060
* @param array $mailsIds Array of mail IDs
* @param string $flag Which you can set are \Seen, \Answered, \Flagged, \Deleted, and \Draft as defined by RFC2060
*/
public function setFlag(array $mailsIds, $flag)
{
$this->imap('setflag_full', [implode(',', $mailsIds), $flag, ST_UID]);
}

/**
* Cause a store to delete the specified flag to the flags set for the mails in the specified sequence.
* Causes a store to delete the specified flag to the flags set for the mails in the specified sequence.
*
* @param string $flag which you can set are \Seen, \Answered, \Flagged, \Deleted, and \Draft as defined by RFC2060
* @param array $mailsIds Array of mail IDs
* @param string $flag Which you can delete are \Seen, \Answered, \Flagged, \Deleted, and \Draft as defined by RFC2060
*/
public function clearFlag(array $mailsIds, $flag)
{
Expand Down Expand Up @@ -661,14 +663,14 @@ public function clearFlag(array $mailsIds, $flag)
* seen - this mail is flagged as already read
* draft - this mail is flagged as being a draft
*
* @return array
* @return array $mailsIds Array of mail IDs
*/
public function getMailsInfo(array $mailsIds)
{
$mails = $this->imap('fetch_overview', [implode(',', $mailsIds), (SE_UID == $this->imapSearchOption) ? FT_UID : 0]);
if (\is_array($mails) && \count($mails)) {
foreach ($mails as &$mail) {
if (isset($mail->subject)) {
if (isset($mail->subject) and !empty($mail->subject)) {
$mail->subject = $this->decodeMimeStr($mail->subject, $this->getServerEncoding());
}
if (isset($mail->from) and !empty($mail->from)) {
Expand Down Expand Up @@ -730,8 +732,8 @@ public function getMailboxInfo()
* SORTCC - mailbox in first cc address
* SORTSIZE - size of mail in octets
*
* @param int $criteria
* @param bool $reverse
* @param int $criteria Sorting criteria (eg. SORTARRIVAL)
* @param bool $reverse Sort reverse or not
* @param string $searchCriteria See http://php.net/imap_search for a complete list of available criteria
*
* @return array Mails ids
Expand All @@ -754,7 +756,7 @@ public function countMails()
/**
* Retrieve the quota settings per user.
*
* @param string Should normally be in the form of which mailbox (i.e. INBOX)
* @param string $quota_root Should normally be in the form of which mailbox (i.e. INBOX)
*
* @return array
*/
Expand All @@ -766,7 +768,7 @@ protected function getQuota($quota_root = 'INBOX')
/**
* Return quota limit in KB.
*
* @param string Should normally be in the form of which mailbox (i.e. INBOX)
* @param string $quota_root Should normally be in the form of which mailbox (i.e. INBOX)
*
* @return int
*/
Expand All @@ -780,7 +782,7 @@ public function getQuotaLimit($quota_root = 'INBOX')
/**
* Return quota usage in KB.
*
* @param string Should normally be in the form of which mailbox (i.e. INBOX)
* @param string $quota_root Should normally be in the form of which mailbox (i.e. INBOX)
*
* @return int FALSE in the case of call failure
*/
Expand All @@ -794,8 +796,10 @@ public function getQuotaUsage($quota_root = 'INBOX')
/**
* Get raw mail data.
*
* @param $msgId
* @param int $msgId ID of the message
* @param bool $markAsSeen Mark the email as seen, when set to true
*
* @return string Message of the fetched body
*/
public function getRawMail($msgId, $markAsSeen = true)
{
Expand All @@ -810,7 +814,7 @@ public function getRawMail($msgId, $markAsSeen = true)
/**
* Get mail header.
*
* @param $mailId
* @param int $mailId ID of the message
*
* @return IncomingMailHeader
*
Expand Down Expand Up @@ -865,7 +869,7 @@ public function getMailHeader($mailId)
foreach ($head->to as $to) {
if (!empty($to->mailbox) && !empty($to->host)) {
$toEmail = strtolower($to->mailbox.'@'.$to->host);
$toName = (isset($to->personal) and !empty($to->personal)) ? $this->decodeMimeStr($to->personal, $this->getServerEncoding()) : null;
$toName = (isset($to->personal) and !empty(trim($to->personal))) ? $this->decodeMimeStr($to->personal, $this->getServerEncoding()) : null;
$toStrings[] = $toName ? "$toName <$toEmail>" : $toEmail;
$header->to[$toEmail] = $toName;
}
Expand All @@ -876,22 +880,33 @@ public function getMailHeader($mailId)
if (isset($head->cc)) {
foreach ($head->cc as $cc) {
if (!empty($cc->mailbox) && !empty($cc->host)) {
$header->cc[strtolower($cc->mailbox.'@'.$cc->host)] = (isset($cc->personal) and !empty($cc->personal)) ? $this->decodeMimeStr($cc->personal, $this->getServerEncoding()) : null;
$ccEmail = strtolower($cc->mailbox.'@'.$cc->host);
$ccName = (isset($cc->personal) and !empty(trim($cc->personal))) ? $this->decodeMimeStr($cc->personal, $this->getServerEncoding()) : null;
$ccStrings[] = $ccName ? "$ccName <$ccEmail>" : $ccEmail;
$header->cc[$ccEmail] = $ccName;
}
}
}

if (isset($head->bcc)) {
foreach ($head->bcc as $bcc) {
if (!empty($bcc->mailbox) && !empty($bcc->host)) {
$header->bcc[strtolower($bcc->mailbox.'@'.$bcc->host)] = (isset($bcc->personal) and !empty($bcc->personal)) ? $this->decodeMimeStr($bcc->personal, $this->getServerEncoding()) : null;
$bccEmail = strtolower($bcc->mailbox.'@'.$bcc->host);
$bccName = (isset($bcc->personal) and !empty(trim($bcc->personal))) ? $this->decodeMimeStr($bcc->personal, $this->getServerEncoding()) : null;
$bccStrings[] = $bccName ? "$bccName <$bccEmail>" : $bccEmail;
$header->bcc[$bccEmail] = $bccName;
}
}
}

if (isset($head->reply_to)) {
foreach ($head->reply_to as $replyTo) {
$header->replyTo[strtolower($replyTo->mailbox.'@'.$replyTo->host)] = (isset($replyTo->personal) and !empty($replyTo->personal)) ? $this->decodeMimeStr($replyTo->personal, $this->getServerEncoding()) : null;
if (!empty($replyTo->mailbox) && !empty($replyTo->host)) {
$replyToEmail = strtolower($replyTo->mailbox.'@'.$replyTo->host);
$replyToName = (isset($replyTo->personal) and !empty(trim($replyTo->personal))) ? $this->decodeMimeStr($replyTo->personal, $this->getServerEncoding()) : null;
$replyToStrings[] = $replyToName ? "$replyToName <$replyToEmail>" : $replyToEmail;
$header->replyTo[$replyToEmail] = $replyToName;
}
}
}

Expand All @@ -902,10 +917,33 @@ public function getMailHeader($mailId)
return $header;
}

/**
* taken from https://www.electrictoolbox.com/php-imap-message-parts/.
*/
public function flattenParts($messageParts, $flattenedParts = [], $prefix = '', $index = 1, $fullPrefix = true)
{
foreach ($messageParts as $part) {
$flattenedParts[$prefix.$index] = $part;
if (isset($part->parts)) {
if (2 == $part->type) {
$flattenedParts = $this->flattenParts($part->parts, $flattenedParts, $prefix.$index.'.', 0, false);
} elseif ($fullPrefix) {
$flattenedParts = $this->flattenParts($part->parts, $flattenedParts, $prefix.$index.'.');
} else {
$flattenedParts = $this->flattenParts($part->parts, $flattenedParts, $prefix);
}
unset($flattenedParts[$prefix.$index]->parts);
}
++$index;
}

return $flattenedParts;
}

/**
* Get mail data.
*
* @param $mailId
* @param int $mailId ID of the mail
* @param bool $markAsSeen Mark the email as seen, when set to true
*
* @return IncomingMail
Expand All @@ -920,8 +958,8 @@ public function getMail($mailId, $markAsSeen = true)
if (empty($mailStructure->parts)) {
$this->initMailPart($mail, $mailStructure, 0, $markAsSeen);
} else {
foreach ($mailStructure->parts as $partNum => $partStructure) {
$this->initMailPart($mail, $partStructure, $partNum + 1, $markAsSeen);
foreach ($this->flattenParts($mailStructure->parts) as $partNum => $partStructure) {
$this->initMailPart($mail, $partStructure, $partNum, $markAsSeen);
}
}

Expand Down Expand Up @@ -979,9 +1017,10 @@ protected function initMailPart(IncomingMail $mail, $partStructure, $partNum, $m
}

// Do NOT parse attachments, when getAttachmentsIgnore() is true
if ($this->getAttachmentsIgnore() &&
(TYPEMULTIPART !== $partStructure->type &&
(TYPETEXT !== $partStructure->type || !\in_array(strtolower($partStructure->subtype), ['plain', 'html'])))) {
if ($this->getAttachmentsIgnore()
&& (TYPEMULTIPART !== $partStructure->type
&& (TYPETEXT !== $partStructure->type || !\in_array(strtolower($partStructure->subtype), ['plain', 'html'])))
) {
return false;
}

Expand Down Expand Up @@ -1282,7 +1321,7 @@ public function getSubscribedMailboxes($search = '*')
*/
public function subscribeMailbox($mailbox)
{
$this->imap('subscribe', $this->imapPath.$this->getPathDelimiter().$mailbox);
$this->imap('subscribe', $this->getCombinedPath($mailbox));
}

/**
Expand All @@ -1294,7 +1333,7 @@ public function subscribeMailbox($mailbox)
*/
public function unsubscribeMailbox($mailbox)
{
$this->imap('unsubscribe', $this->imapPath.$this->getPathDelimiter().$mailbox);
$this->imap('unsubscribe', $this->getCombinedPath($mailbox));
}

/**
Expand Down Expand Up @@ -1352,4 +1391,29 @@ public function imap($methodShortName, $args = [], $prependConnectionAsFirstArg

return $result;
}

/**
* Combine Subfolder or Folder to the connection.
* Have the imapPath a folder added to the connection info, then will the $folder added as subfolder.
* If the parameter $absolute TRUE, then will the connection new builded only with this folder as root element.
*
* @param string $folder Folder, the will added to the path
* @param bool $absolute Add folder as root element to the connection and remove all other from this
*
* @return string Return the new path
*/
protected function getCombinedPath(string $folder, bool $absolute = false)
{
if (!empty($folder)) {
if ('}' === substr($this->imapPath, -1) || true === $absolute) {
$posConnectionDefinitionEnd = strpos($this->imapPath, '}');

return substr($this->imapPath, 0, $posConnectionDefinitionEnd + 1).$folder;
} else {
return $this->imapPath.$this->getPathDelimiter().$folder;
}
}

return $this->imapPath;
}
}