Returns all email addresses contained in the email headers. This includes, to, from, cc, and bcc.

@param Part[] $parts
@param array  $fields

@return array
342221
private function getAllEmailAddresses($parts, $fields = ['to', 'from', 'cc', 'bcc'])
    {
        $addresses = [];
        foreach ($fields as $field) {
            $addressesPerField = [];
            foreach ($parts as $part) {
                 $addressesPerField = array_merge(
                     $addressesPerField,
                     $this->getAddressesFromFieldInPart($field, $part)
                 );
            }
            $addresses[$field] = $addressesPerField;
        }

        return $addresses;
    }
466010
protected static function tokenize( array $parts ) {
		$tokens = [];
		$index  = 0;

		foreach ( $parts as $part ) {
			if ( \preg_match( self::_RE_SPACE, $part ) ) {
				$tokens[ $index ] = new Token( $part, Token::SPACE );
			} elseif ( \preg_match( self::_RE_PUNCTUATION, $part ) ) {
				$tokens[ $index ] = new Token( $part, Token::PUNCTUATION );
			} elseif ( \preg_match( self::_RE_WORD, $part ) ) {
				// Make sure that things like email addresses and URLs are not broken up
				// into words and punctuation not preceeded by an 'other'.
				self::parse_ambiguous_token( Token::WORD, $part, $tokens, $index );
			} else {
				// Make sure that things like email addresses and URLs are not broken up into words
				// and punctuation not preceeded by an 'other' or 'word'.
				self::parse_ambiguous_token( Token::OTHER, $part, $tokens, $index );
			}

			$index++;
		}

		return $tokens;
	}
1009655
private function extractPartsRecursive(stdClass $partStructure, $partNum)
    {
        $partStructure->number = $partNum;

        $parts = [];
        $parts[] = $partStructure;

        if (false === isset($partStructure->parts) || [] === $partStructure->parts) {
            return $parts;
        }

        foreach ($partStructure->parts as $subPartNum => $subPartStructure) {
            $nextPartNumber = $partNum.'.'.($subPartNum + 1);

            $type = $partStructure->type;
            $subType = $partStructure->subtype;

            if ($type == TYPEMESSAGE && $subType == ImapMailBodyPartStructureInterface::SUBTYPE_RFC822) {
                $nextPartNumber = $partNum;
            }

            $parts = array_merge($parts, $this->extractPartsRecursive($subPartStructure, $nextPartNumber));
        }

        return $parts;
    }
1158887
protected function _splitCheck($parts, $char)
    {
        $string = $parts[0];

        for ($i = 0; $i < count($parts); $i++) {
            if ($this->_hasUnclosedQuotes($string)
                || $this->_hasUnclosedBrackets($string, '<>')
                || $this->_hasUnclosedBrackets($string, '[]')
                || $this->_hasUnclosedBrackets($string, '()')
                || substr($string, -1) == '\\') {
                if (isset($parts[$i + 1])) {
                    $string = $string . $char . $parts[$i + 1];
                } else {
                    $this->error = 'Invalid address spec. Unclosed bracket or quotes';
                    return false;
                }
            } else {
                $this->index = $i;
                break;
            }
        }

        return $string;
    }
56873
public function getLinkPart($field, $part)
    {
        $link_attr = self::decodeLinkObject($this->get($field));
        if ($part === 'body') {
            $part = 'title';
        }
        return $link_attr->$part;
    }
140139
protected function processParts(array $parts)
    {
        $strValue = '';
        $filtered = $this->filterIgnoredSpaces($parts);
        foreach ($filtered as $part) {
            $strValue .= $part->getValue();
        }
        return [$this->partFactory->newLiteralPart($strValue)];
    }
1258368
private static function gatherAttachments(PartInterface $part): array
    {
        $attachments = [];
        foreach ($part->getParts() as $childPart) {
            if ($childPart instanceof Attachment) {
                $attachments[] = $childPart;
            }
            if ($childPart->hasChildren()) {
                $attachments = \array_merge($attachments, self::gatherAttachments($childPart));
            }
        }

        return $attachments;
    }
551661
private function buildQuery($parts)
    {
        $return = array();
        foreach ($parts as $key => $value) {
            if (is_array($value)) {
                foreach ($value as $v) {
                    $return[] = urlencode($key) . "=" . urlencode($v);
                }
                continue;
            }
            $return[] = urlencode($key) . "=" . urlencode($value);
        }
        return implode('&', $return);
    }
432996
private function filterNameAddresses(array $recipients)
    {
        $filtered = [];

        foreach ($recipients as $address => $name) {
            if ($this->isWhitelisted($address)) {
                $filtered[$address] = $name;
            }
        }

        return $filtered;
    }
795406
public function getHeaders(array $include = [])
    {
        if ($include == array_values($include)) {
            $include = array_fill_keys($include, true);
        }
        $defaults = array_fill_keys(
            [
                'from', 'sender', 'replyTo', 'readReceipt', 'returnPath',
                'to', 'cc', 'bcc', 'subject'],
            false
        );
        $include += $defaults;

        $headers = [];
        $relation = [
            'from' => 'From',
            'replyTo' => 'Reply-To',
            'readReceipt' => 'Disposition-Notification-To',
            'returnPath' => 'Return-Path'
        ];
        foreach ($relation as $var => $header) {
            if ($include[$var]) {
                $var = '_' . $var;
                $headers[$header] = current($this->_formatAddress($this->{$var}));
            }
        }
        if ($include['sender']) {
            if (key($this->_sender) === key($this->_from)) {
                $headers['Sender'] = '';
            } else {
                $headers['Sender'] = current($this->_formatAddress($this->_sender));
            }
        }

        foreach (['to', 'cc', 'bcc'] as $var) {
            if ($include[$var]) {
                $classVar = '_' . $var;
                $headers[ucfirst($var)] = implode(', ', $this->_formatAddress($this->{$classVar}));
            }
        }

        $headers += $this->_headers;
        if (!isset($headers['Date'])) {
            $headers['Date'] = date(DATE_RFC2822);
        }
        if ($this->_messageId !== false) {
            if ($this->_messageId === true) {
                $this->_messageId = '<' . str_replace('-', '', Text::uuid()) . '@' . $this->_domain . '>';
            }

            $headers['Message-ID'] = $this->_messageId;
        }

        if ($this->_priority) {
            $headers['X-Priority'] = $this->_priority;
        }

        if ($include['subject']) {
            $headers['Subject'] = $this->_subject;
        }

        $headers['MIME-Version'] = '1.0';
        if ($this->_attachments) {
            $headers['Content-Type'] = 'multipart/mixed; boundary="' . $this->_boundary . '"';
        } elseif ($this->_emailFormat === 'both') {
            $headers['Content-Type'] = 'multipart/alternative; boundary="' . $this->_boundary . '"';
        } elseif ($this->_emailFormat === 'text') {
            $headers['Content-Type'] = 'text/plain; charset=' . $this->_getContentTypeCharset();
        } elseif ($this->_emailFormat === 'html') {
            $headers['Content-Type'] = 'text/html; charset=' . $this->_getContentTypeCharset();
        }
        $headers['Content-Transfer-Encoding'] = $this->_getContentTransferEncoding();

        return $headers;
    }
362598
protected function getRespondentMailfields()
    {
        if ($this->respondent) {
            $result = array();
            $result['bcc']          = $this->mailFields['project_bcc'];
            $result['email']        = $this->respondent->getEmailAddress();
            $result['from']         = '';
            $result['first_name']   = $this->respondent->getFirstName();
            $result['full_name']    = $this->respondent->getFullName();
            $result['greeting']     = $this->respondent->getGreeting();
            $result['last_name']    = $this->respondent->getLastName();
            $result['name']         = $this->respondent->getName();
        } else {
            $result = array(
                'email'     => '',
                'from'      => '',
                'first_name'=> '',
                'full_name' => '',
                'greeting'  => '',
                'last_name' => '',
                'name'      => ''
            );
        }

        $result['reply_to']       = $result['from'];
        $result['to']             = $result['email'];
        $result['reset_ask']      = '';
        if ($this->mailFields['organization_login_url']) {
            $result['reset_ask']      = $this->mailFields['organization_login_url'] . '/index/resetpassword';
        }
        return $result;
    }
161717
protected function parse($part) {
			$subPos = strpos($part, self::TOKEN_SUBFIELD_OPEN);

			if ($subPos === false)
				return [$part => true];

			$key = substr($part, 0, $subPos++);
			$fields = [];

			$subSelector = substr($part, $subPos, -1);
			$subLength = strlen($subSelector);
			$subPos = 0;

			while ($fragment = $this->getNextFragment($subSelector, $subLength, $subPos))
				if (($index = strpos($fragment, self::TOKEN_SUBFIELD_OPEN)) !== false) {
					$subfields = $this->parse($fragment);

					foreach ($subfields as $k => $v)
						$fields[$k] = $v;
				} else
					$fields[$fragment] = true;

			return [$key => $fields];
		}
555577
protected function structure_part($part, $count = 0, $parent = '', $mime_headers = null)
    {
        $struct = new rcube_message_part;
        $struct->mime_id = empty($parent) ? (string)$count : "$parent.$count";

        // multipart
        if (is_array($part[0])) {
            $struct->ctype_primary = 'multipart';

        /* RFC3501: BODYSTRUCTURE fields of multipart part
            part1 array
            part2 array
            part3 array
            ....
            1. subtype
            2. parameters (optional)
            3. description (optional)
            4. language (optional)
            5. location (optional)
        */

            // find first non-array entry
            for ($i=1; $i<count($part); $i++) {
                if (!is_array($part[$i])) {
                    $struct->ctype_secondary = strtolower($part[$i]);

                    // read content type parameters
                    if (is_array($part[$i+1])) {
                        $struct->ctype_parameters = array();
                        for ($j=0; $j<count($part[$i+1]); $j+=2) {
                            $param = strtolower($part[$i+1][$j]);
                            $struct->ctype_parameters[$param] = $part[$i+1][$j+1];
                        }
                    }

                    break;
                }
            }

            $struct->mimetype = 'multipart/'.$struct->ctype_secondary;

            // build parts list for headers pre-fetching
            for ($i=0; $i<count($part); $i++) {
                if (!is_array($part[$i])) {
                    break;
                }
                // fetch message headers if message/rfc822
                // or named part (could contain Content-Location header)
                if (!is_array($part[$i][0])) {
                    $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
                    if (strtolower($part[$i][0]) == 'message' && strtolower($part[$i][1]) == 'rfc822') {
                        $mime_part_headers[] = $tmp_part_id;
                    }
                    else if (in_array('name', (array)$part[$i][2]) && empty($part[$i][3])) {
                        $mime_part_headers[] = $tmp_part_id;
                    }
                }
            }

            // pre-fetch headers of all parts (in one command for better performance)
            // @TODO: we could do this before _structure_part() call, to fetch
            // headers for parts on all levels
            if ($mime_part_headers) {
                $mime_part_headers = $this->conn->fetchMIMEHeaders($this->folder,
                    $this->msg_uid, $mime_part_headers);
            }

            $struct->parts = array();
            for ($i=0, $count=0; $i<count($part); $i++) {
                if (!is_array($part[$i])) {
                    break;
                }
                $tmp_part_id = $struct->mime_id ? $struct->mime_id.'.'.($i+1) : $i+1;
                $struct->parts[] = $this->structure_part($part[$i], ++$count, $struct->mime_id,
                    $mime_part_headers[$tmp_part_id]);
            }

            return $struct;
        }

        /* RFC3501: BODYSTRUCTURE fields of non-multipart part
            0. type
            1. subtype
            2. parameters
            3. id
            4. description
            5. encoding
            6. size
          -- text
            7. lines
          -- message/rfc822
            7. envelope structure
            8. body structure
            9. lines
          --
            x. md5 (optional)
            x. disposition (optional)
            x. language (optional)
            x. location (optional)
        */

        // regular part
        $struct->ctype_primary = strtolower($part[0]);
        $struct->ctype_secondary = strtolower($part[1]);
        $struct->mimetype = $struct->ctype_primary.'/'.$struct->ctype_secondary;

        // read content type parameters
        if (is_array($part[2])) {
            $struct->ctype_parameters = array();
            for ($i=0; $i<count($part[2]); $i+=2) {
                $struct->ctype_parameters[strtolower($part[2][$i])] = $part[2][$i+1];
            }

            if (isset($struct->ctype_parameters['charset'])) {
                $struct->charset = $struct->ctype_parameters['charset'];
            }
        }

        // #1487700: workaround for lack of charset in malformed structure
        if (empty($struct->charset) && !empty($mime_headers) && $mime_headers->charset) {
            $struct->charset = $mime_headers->charset;
        }

        // read content encoding
        if (!empty($part[5])) {
            $struct->encoding = strtolower($part[5]);
            $struct->headers['content-transfer-encoding'] = $struct->encoding;
        }

        // get part size
        if (!empty($part[6])) {
            $struct->size = intval($part[6]);
        }

        // read part disposition
        $di = 8;
        if ($struct->ctype_primary == 'text') {
            $di += 1;
        }
        else if ($struct->mimetype == 'message/rfc822') {
            $di += 3;
        }

        if (is_array($part[$di]) && count($part[$di]) == 2) {
            $struct->disposition = strtolower($part[$di][0]);
            if ($struct->disposition && $struct->disposition !== 'inline' && $struct->disposition !== 'attachment') {
                // RFC2183, Section 2.8 - unrecognized type should be treated as "attachment"
                $struct->disposition = 'attachment';
            }
            if (is_array($part[$di][1])) {
                for ($n=0; $n<count($part[$di][1]); $n+=2) {
                    $struct->d_parameters[strtolower($part[$di][1][$n])] = $part[$di][1][$n+1];
                }
            }
        }

        // get message/rfc822's child-parts
        if (is_array($part[8]) && $di != 8) {
            $struct->parts = array();
            for ($i=0, $count=0; $i<count($part[8]); $i++) {
                if (!is_array($part[8][$i])) {
                    break;
                }
                $struct->parts[] = $this->structure_part($part[8][$i], ++$count, $struct->mime_id);
            }
        }

        // get part ID
        if (!empty($part[3])) {
            $struct->content_id = $part[3];
            $struct->headers['content-id'] = $part[3];

            if (empty($struct->disposition)) {
                $struct->disposition = 'inline';
            }
        }

        // fetch message headers if message/rfc822 or named part (could contain Content-Location header)
        if ($struct->ctype_primary == 'message' || ($struct->ctype_parameters['name'] && !$struct->content_id)) {
            if (empty($mime_headers)) {
                $mime_headers = $this->conn->fetchPartHeader(
                    $this->folder, $this->msg_uid, true, $struct->mime_id);
            }

            if (is_string($mime_headers)) {
                $struct->headers = rcube_mime::parse_headers($mime_headers) + $struct->headers;
            }
            else if (is_object($mime_headers)) {
                $struct->headers = get_object_vars($mime_headers) + $struct->headers;
            }

            // get real content-type of message/rfc822
            if ($struct->mimetype == 'message/rfc822') {
                // single-part
                if (!is_array($part[8][0])) {
                    $struct->real_mimetype = strtolower($part[8][0] . '/' . $part[8][1]);
                }
                // multi-part
                else {
                    for ($n=0; $n<count($part[8]); $n++) {
                        if (!is_array($part[8][$n])) {
                            break;
                        }
                    }
                    $struct->real_mimetype = 'multipart/' . strtolower($part[8][$n]);
                }
            }

            if ($struct->ctype_primary == 'message' && empty($struct->parts)) {
                if (is_array($part[8]) && $di != 8) {
                    $struct->parts[] = $this->structure_part($part[8], ++$count, $struct->mime_id);
                }
            }
        }

        // normalize filename property
        $this->set_part_filename($struct, $mime_headers);

        return $struct;
    }
28443
static public function parsePartHeaders( ezcMailHeadersHolder $headers, ezcMailPart $part )
    {
        if ( isset( $headers['Content-Disposition'] ) )
        {
            $part->contentDisposition = ezcMailRfc2231Implementation::parseContentDisposition( $headers['Content-Disposition'] );
        }
    }
677983
public function getPartHeaders($partnum, $EOL = Zend_Mime::LINEEND)
    {
        return $this->_parts[$partnum]->getHeaders($EOL);
    }
968784
public function toString(array $parts = array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'))
	{
		// Make sure the query is created
		$query = $this->getQuery();

		$uri = '';
		$uri .= in_array('scheme', $parts) ? (!empty($this->scheme) ? $this->scheme . '://' : '') : '';
		$uri .= in_array('user', $parts) ? $this->user : '';
		$uri .= in_array('pass', $parts) ? (!empty($this->pass) ? ':' : '') . $this->pass . (!empty($this->user) ? '@' : '') : '';
		$uri .= in_array('host', $parts) ? $this->host : '';
		$uri .= in_array('port', $parts) ? (!empty($this->port) ? ':' : '') . $this->port : '';
		$uri .= in_array('path', $parts) ? $this->path : '';
		$uri .= in_array('query', $parts) ? (!empty($query) ? '?' . $query : '') : '';
		$uri .= in_array('fragment', $parts) ? (!empty($this->fragment) ? '#' . $this->fragment : '') : '';

		return $uri;
	}
1134796
private static function explodePath($parts)
    {
        if (!is_array($parts)) {
            $parts = explode(self::$delimiter, $parts);
        }

        return $parts;
    }