/** * Constructor. * * @param string $str The subject string. * @param array $opts Additional options: * - keepblob: (boolean) Don't remove any "blob" information (i.e. text * leading text between square brackets) from string. * * @return string The cleaned up subject string. */ public function __construct($str, array $opts = array()) { // Rule 1a: MIME decode. $str = Horde_Mime::decode($str); // Rule 1b: Remove superfluous whitespace. $str = preg_replace("/[\t\r\n ]+/", ' ', $str); do { /* (2) Remove all trailing text of the subject that matches the * the subj-trailer ABNF, repeat until no more matches are * possible. */ $str = preg_replace("/(?:\\s*\\(fwd\\)\\s*)+\$/i", '', $str); do { /* (3) Remove all prefix text of the subject that matches the * subj-leader ABNF. */ $found = $this->_removeSubjLeader($str, !empty($opts['keepblob'])); /* (4) If there is prefix text of the subject that matches * the subj-blob ABNF, and removing that prefix leaves a * non-empty subj-base, then remove the prefix text. */ $found = empty($opts['keepblob']) && $this->_removeBlobWhenNonempty($str) || $found; /* (5) Repeat (3) and (4) until no matches remain. */ } while ($found); /* (6) If the resulting text begins with the subj-fwd-hdr ABNF and * ends with the subj-fwd-trl ABNF, remove the subj-fwd-hdr and * subj-fwd-trl and repeat from step (2). */ } while ($this->_removeSubjFwdHdr($str)); $this->_subject = strval($str); }
/** */ public function __set($name, $value) { switch ($name) { case 'groupname': $this->_groupname = Horde_Mime::decode($value); break; } }
/** */ protected function _setValue($value) { if ($value instanceof Horde_Mime_Headers_Element) { $value = $value->value; } foreach (is_array($value) ? $value : array($value) as $val) { $this->_values[] = $this->_sanityCheck(Horde_Mime::decode($val)); } }
/** */ protected function _setValue($value) { if ($value instanceof Horde_Mime_Headers_Element) { $value = $value->value; } elseif (is_array($value)) { $value = reset($value); } $this->_values = array($this->_sanityCheck(Horde_Mime::decode($value))); }
/** * @param mixed $value Either a single language or an array of languages. */ protected function _setValue($value) { if ($value instanceof Horde_Mime_Headers_Element) { $value = $value->value; } if (!is_array($value)) { $value = array_map('trim', explode(',', $value)); } $this->_values = array(); foreach ($value as $val) { $this->_values[] = Horde_String::lower($this->_sanityCheck(Horde_Mime::decode($val))); } }
public function testGenerate() { $h = new Horde_Mime_Headers(); $ob = new Horde_Mime_Mdn($h); try { $ob->generate(true, true, 'deleted', 'foo', null); $this->fail('Expected Exception'); } catch (RuntimeException $e) { } $date = 'Tue, 18 Nov 2014 20:14:17 -0700'; $mdn_addr = 'Aäb <*****@*****.**>'; $h->addHeader('Date', $date); $h->addHeader('Subject', 'Test'); $h->addHeader('To', '"BAR" <*****@*****.**>'); $ob->addMdnRequestHeaders($mdn_addr); $mailer = new Horde_Mail_Transport_Mock(); $ob->generate(true, true, 'displayed', 'test.example.com', $mailer, array('from_addr' => '*****@*****.**'), array('error'), array('error' => 'Foo')); $sent = str_replace("\r\n", "\n", $mailer->sentMessages[0]); $this->assertEquals('auto-replied', $sent['headers']['Auto-Submitted']); $this->assertEquals('*****@*****.**', $sent['headers']['From']); $this->assertEquals($mdn_addr, Horde_Mime::decode($sent['headers']['To'])); $this->assertEquals('Disposition Notification', $sent['headers']['Subject']); $this->assertStringMatchesFormat('This message is in MIME format. --=%s Content-Type: text/plain; format=flowed; DelSp=Yes The message sent on Tue, 18 Nov 2014 20:14:17 -0700 to BAR <*****@*****.**> with subject "Test" has been displayed. This is no guarantee that the message has been read or understood. --=%s Content-Type: message/disposition-notification Reporting-UA: test.example.com; Horde Application Framework 5 Final-Recipient: rfc822;bar@example.com Disposition: manual-action/MDN-sent-manually; displayed/error Error: Foo --=%s Content-Type: message/rfc822 Date: Tue, 18 Nov 2014 20:14:17 -0700 Subject: Test To: BAR <*****@*****.**> Disposition-Notification-To: =?utf-8?b?QcOkYg==?= <*****@*****.**> --=%s ', $sent['body']); }
/** * Recursively parse BODYSTRUCTURE data from a FETCH return (see * RFC 3501 [7.4.2]). * * @param Horde_Imap_Client_Tokenize $data Data returned from the server. * * @return array The array of bodystructure information. */ protected function _parseBodystructure(Horde_Imap_Client_Tokenize $data) { $ob = new Horde_Mime_Part(); // If index 0 is an array, this is a multipart part. if (is_object($entry = $data->rewind())) { // Keep going through array values until we find a non-array. do { $ob->addPart($this->_parseBodystructure($entry)); } while (is_object($entry = $data->next())); // The first string entry after an array entry gives us the // subpart type. $ob->setType('multipart/' . $entry); // After the subtype is further extension information. This // information MAY not appear for BODYSTRUCTURE requests. // This is parameter information. if (is_object($tmp = $data->next())) { foreach ($this->_parseStructureParams($tmp, 'content-type') as $key => $val) { $ob->setContentTypeParameter($key, $val); } } } else { $ob->setType($entry . '/' . $data->next()); if (is_object($tmp = $data->next())) { foreach ($this->_parseStructureParams($tmp, 'content-type') as $key => $val) { $ob->setContentTypeParameter($key, $val); } } if (!is_null($tmp = $data->next())) { $ob->setContentId($tmp); } if (!is_null($tmp = $data->next())) { $ob->setDescription(Horde_Mime::decode($tmp)); } if (!is_null($tmp = $data->next())) { $ob->setTransferEncoding($tmp); } $ob->setBytes($data->next()); // If the type is 'message/rfc822' or 'text/*', several extra // fields are included switch ($ob->getPrimaryType()) { case 'message': if ($ob->getSubType() == 'rfc822') { $data->next(); // Ignore: envelope $ob->addPart($this->_parseBodystructure($data->next())); $data->next(); // Ignore: lines } break; case 'text': $data->next(); // Ignore: lines break; } // After the subtype is further extension information. This // information MAY appear for BODYSTRUCTURE requests. $data->next(); // Ignore: MD5 } // This is disposition information if (is_object($tmp = $data->next())) { $ob->setDisposition($tmp->rewind()); foreach ($this->_parseStructureParams($tmp->next(), 'content-disposition') as $key => $val) { $ob->setDispositionParameter($key, $val); } } // This is language information. It is either a single value or a list // of values. if (($tmp = $data->next()) !== false) { $ob->setLanguage($tmp); } $data->next(); // Ignore: location (RFC 2557) return $ob; }
/** */ public function __set($name, $value) { switch ($name) { case 'host': try { $value = Horde_Idna::decode($value); } catch (Horde_Idna_Exception $e) { } $this->_host = Horde_String::lower($value); break; case 'personal': $this->_personal = strlen($value) ? Horde_Mime::decode($value) : null; break; } }
/** */ public function __set($name, $value) { switch ($name) { case 'host': $value = ltrim($value, '@'); $this->_host = function_exists('idn_to_utf8') ? strtolower(idn_to_utf8($value)) : strtolower($value); break; case 'personal': $this->_personal = strlen($value) ? Horde_Mime::decode($value) : null; break; } }
/** * Add a header to the header array. * * @param string $header The header name. * @param string $value The header value (UTF-8). * @param array $opts Additional options: * - params: (array) MIME parameters for Content-Type or * Content-Disposition. * DEFAULT: None * - sanity_check: (boolean) Do sanity-checking on header value? * DEFAULT: false */ public function addHeader($header, $value, array $opts = array()) { $header = trim($header); $lcHeader = Horde_String::lower($header); if (!isset($this->_headers[$lcHeader])) { $this->_headers[$lcHeader] = array('h' => $header); } $ptr =& $this->_headers[$lcHeader]; if (!empty($opts['sanity_check'])) { $value = $this->_sanityCheck($value); } // Fields defined in RFC 2822 that contain address information if (in_array($lcHeader, $this->addressFields())) { $rfc822 = new Horde_Mail_Rfc822(); $addr_list = $rfc822->parseAddressList($value); switch ($lcHeader) { case 'bcc': case 'cc': case 'from': case 'to': /* Catch malformed undisclosed-recipients entries. */ if (count($addr_list) == 1 && preg_match("/^\\s*undisclosed-recipients:?\\s*\$/i", $addr_list[0]->bare_address)) { $addr_list = new Horde_Mail_Rfc822_List('undisclosed-recipients:;'); } break; } $value = strval($addr_list); } else { $value = Horde_Mime::decode($value); } if (isset($ptr['v'])) { if (!is_array($ptr['v'])) { $ptr['v'] = array($ptr['v']); } $ptr['v'][] = $value; } else { $ptr['v'] = $value; } if (!empty($opts['params'])) { $ptr['p'] = $opts['params']; } }
/** * AJAX action: Delete an attachment from compose data. * * Variables used: * - atc_indices: (string) [JSON array] Attachment IDs to delete. * - imp_compose: (string) The IMP_Compose cache identifier. * - quiet: (boolean) If true, don't output notifications. * * @return array The list of attchment IDs that were deleted. */ public function deleteAttach() { global $injector, $notification; $result = array(); if (isset($this->vars->atc_indices)) { $imp_compose = $injector->getInstance('IMP_Factory_Compose')->create($this->vars->imp_compose); foreach (json_decode($this->vars->atc_indices) as $val) { if (isset($imp_compose[$val])) { if (empty($this->vars->quiet)) { $notification->push(sprintf(_("Deleted attachment \"%s\"."), Horde_Mime::decode($imp_compose[$val]->getPart()->getName(true))), 'horde.success'); } unset($imp_compose[$val]); $result[] = $val; $this->_base->queue->compose($imp_compose); } } } if (empty($result) && empty($this->vars->quiet)) { $notification->push(_("At least one attachment could not be deleted."), 'horde.error'); } return $result; }
public function testDecode() { $this->assertEquals(' François Xavier. XXXXXX <*****@*****.**>', Horde_Mime::decode('=?utf-8?Q?_Fran=C3=A7ois_Xavier=2E_XXXXXX_?= <*****@*****.**>')); /* Not MIME encoded. */ $this->assertEquals('=? required=?', Horde_Mime::decode('=? required=?')); }
/** * @dataProvider decodeProvider */ public function testDecode($data, $expected) { $this->assertEquals($expected, Horde_Mime::decode($data)); }
/** * Recursively parse BODYSTRUCTURE data from a FETCH return (see * RFC 3501 [7.4.2]). * * @param array $data The tokenized information from the server. * * @return array The array of bodystructure information. */ protected function _parseStructure($data) { $ob = new Horde_Mime_Part(); // If index 0 is an array, this is a multipart part. if (is_array($data[0])) { // Keep going through array values until we find a non-array. for ($i = 0, $cnt = count($data); $i < $cnt; ++$i) { if (!is_array($data[$i])) { break; } $ob->addPart($this->_parseStructure($data[$i])); } // The first string entry after an array entry gives us the // subpart type. $ob->setType('multipart/' . $data[$i]); // After the subtype is further extension information. This // information MAY not appear for BODYSTRUCTURE requests. // This is parameter information. if (isset($data[++$i]) && is_array($data[$i])) { foreach ($this->_parseStructureParams($data[$i], 'content-type') as $key => $val) { $ob->setContentTypeParameter($key, $val); } } // This is disposition information. if (isset($data[++$i]) && is_array($data[$i])) { $ob->setDisposition($data[$i][0]); foreach ($this->_parseStructureParams($data[$i][1], 'content-disposition') as $key => $val) { $ob->setDispositionParameter($key, $val); } } // This is language information. It is either a single value or // a list of values. if (isset($data[++$i])) { $ob->setLanguage($data[$i]); } // Ignore: location (RFC 2557) // There can be further information returned in the future, but // for now we are done. } else { $ob->setType($data[0] . '/' . $data[1]); foreach ($this->_parseStructureParams($data[2], 'content-type') as $key => $val) { $ob->setContentTypeParameter($key, $val); } if ($data[3] !== null) { $ob->setContentId($data[3]); } if ($data[4] !== null) { $ob->setDescription(Horde_Mime::decode($data[4])); } if ($data[5] !== null) { $ob->setTransferEncoding($data[5]); } if ($data[6] !== null) { $ob->setBytes($data[6]); } // If the type is 'message/rfc822' or 'text/*', several extra // fields are included switch ($ob->getPrimaryType()) { case 'message': if ($ob->getSubType() == 'rfc822') { // Ignore: envelope $ob->addPart($this->_parseStructure($data[8])); // Ignore: lines $i = 10; } else { $i = 7; } break; case 'text': // Ignore: lines $i = 8; break; default: $i = 7; break; } // After the subtype is further extension information. This // information MAY appear for BODYSTRUCTURE requests. // Ignore: MD5 // This is disposition information if (isset($data[++$i]) && is_array($data[$i])) { $ob->setDisposition($data[$i][0]); foreach ($this->_parseStructureParams($data[$i][1], 'content-disposition') as $key => $val) { $ob->setDispositionParameter($key, $val); } } // This is language information. It is either a single value or // a list of values. if (isset($data[++$i])) { $ob->setLanguage($data[$i]); } // Ignore: location (RFC 2557) } return $ob; }
/** * Decodes a MIME content parameter string pursuant to RFC 2183 & 2231 * (Content-Type and Content-Disposition headers). * * Stores value/parameter data in the current object. * * @param mixed $data Parameter data. Either an array or a string. */ public function decode($data) { $add = $convert = array(); if (is_array($data)) { $params = $data; } else { $parts = explode(';', $data, 2); if (isset($parts[0]) && strpos($parts[0], '=') === false) { $this->setContentParamValue($parts[0]); $param = isset($parts[1]) ? $parts[1] : null; } else { $param = $data; } if (empty($param)) { $params = array(); } else { $decode = new Horde_Mime_ContentParam_Decode(); $params = $decode->decode($param); } } $to_add = array(); foreach ($params as $name => $val) { /* Asterisk at end indicates encoded value. */ if (substr($name, -1) == '*') { $name = substr($name, 0, -1); $encoded = true; } else { $encoded = false; } /* This asterisk indicates continuation parameter. */ if (($pos = strrpos($name, '*')) !== false && is_numeric($order = substr($name, $pos + 1))) { $name = substr($name, 0, $pos); $to_add[Horde_String::lower($name)][$order] = $val; } else { $to_add[$name] = array($val); } if ($encoded) { $convert[$name] = true; } } foreach ($to_add as $key => $val) { ksort($val); $add[$key] = implode('', $val); } foreach (array_keys($convert) as $name) { $val = $add[$name]; $quote = strpos($val, "'"); if ($quote === false) { $add[$name] = urldecode($val); } else { $orig_charset = substr($val, 0, $quote); if (Horde_String::lower($orig_charset) == 'iso-8859-1') { $orig_charset = 'windows-1252'; } /* Ignore language. */ $quote = strpos($val, "'", $quote + 1); substr($val, $quote + 1); $add[$name] = Horde_String::convertCharset(urldecode(substr($val, $quote + 1)), $orig_charset, 'UTF-8'); } } /* MIME parameters are supposed to be encoded via RFC 2231, but many * mailers do RFC 2045 encoding instead. However, if we see at least * one RFC 2231 encoding, then assume the sending mailer knew what * it was doing and didn't send any parameters RFC 2045 encoded. */ if (empty($convert)) { foreach ($add as $key => $val) { $add[$key] = Horde_Mime::decode($val); } } if (count($add)) { foreach ($add as $key => $val) { /* When parsing a content-param string, lowercase all * parameter names to normalize. Only maintain case of * parameters explicitly added by calling code. */ $this[Horde_String::lower($key)] = $val; } } elseif (is_string($data)) { $this->setContentParamValue($parts[0]); } }
/** * Performs the filtering specified in the rules. * * @param integer $change The timestamp of the latest rule change during * the current session. */ protected function _perform($change) { $api = $this->_params['api']; $notification = $this->_params['notification']; /* Indices that will be ignored by subsequent rules. */ $ignore_ids = array(); /* Only do filtering if: 1. We have not done filtering before -or- 2. The mailbox has changed -or- 3. The rules have changed. */ $cache = $api->getCache(); if ($cache !== false && $cache == $change) { return; } $filters = Ingo_Storage_FilterIterator_Skip::create($this->_params['storage'], $this->_params['skip']); /* Parse through the rules, one-by-one. */ foreach ($filters as $rule) { /* Check to make sure this is a valid rule and that the rule is not disabled. */ if (!$this->_validRule($rule) || $rule->disable) { continue; } switch ($class = get_class($rule)) { case 'Ingo_Rule_System_Blacklist': case 'Ingo_Rule_System_Whitelist': $addr = $rule->addresses; $bl_folder = $class === 'Ingo_Rule_System_Blacklist' ? $rule->mailbox : null; /* If list is empty, move on. */ if (empty($addr)) { continue; } $addr = new Horde_Mail_Rfc822_List($addr); $query = $this->_getQuery(); $or_ob = new Horde_Imap_Client_Search_Query(); foreach ($addr->bare_addresses as $val) { $ob = new Horde_Imap_Client_Search_Query(); $ob->charset('UTF-8', false); $ob->headerText('from', $val); $or_ob->orSearch(array($ob)); } $query->andSearch(array($or_ob)); $indices = $api->search($query); if (!($msgs = $api->fetchEnvelope($indices))) { continue; } /* Remove any indices that got in there by way of partial * address match. */ $remove = array(); foreach ($msgs as $v) { foreach ($v->getEnvelope()->from as $v2) { if (!$addr->contains($v2)) { $remove[] = $v->getUid(); break; } } } if ($remove) { $indices = array_diff($indices, $remove); } if ($class === 'Ingo_Rule_System_Blacklist') { $indices = array_diff($indices, $ignore_ids); if (!empty($indices)) { if (!empty($bl_folder)) { $api->moveMessages($indices, $bl_folder); } else { $api->deleteMessages($indices); } $notification->push(sprintf(_("Filter activity: %s message(s) that matched the blacklist were deleted."), count($indices)), 'horde.message'); } } else { $ignore_ids = $indices; } break; case 'Ingo_Rule_User_Discard': case 'Ingo_Rule_User_Keep': case 'Ingo_Rule_User_Move': case 'Ingo_Rule_User_MoveKeep': $base_query = $this->_getQuery(); $query = new Horde_Imap_Client_Search_Query(); foreach ($rule->conditions as $val) { $ob = new Horde_Imap_Client_Search_Query(); if (!empty($val['type']) && $val['type'] == Ingo_Rule_User::TEST_SIZE) { $ob->size($val['value'], $val['match'] == 'greater than'); } elseif (!empty($val['type']) && $val['type'] == Ingo_Rule_User::TEST_BODY) { $ob->charset('UTF-8', false); $ob->text($val['value'], true, $val['match'] == 'not contain'); } else { if (strpos($val['field'], ',') == false) { $ob->charset('UTF-8', false); $ob->headerText($val['field'], $val['value'], $val['match'] == 'not contain'); } else { foreach (explode(',', $val['field']) as $header) { $hdr_ob = new Horde_Imap_Client_Search_Query(); $hdr_ob->charset('UTF-8', false); $hdr_ob->headerText($header, $val['value'], $val['match'] == 'not contain'); if ($val['match'] == 'contains') { $ob->orSearch(array($hdr_ob)); } elseif ($val['match'] == 'not contain') { $ob->andSearch(array($hdr_ob)); } } } } switch ($rule->combine) { case Ingo_Rule_User::COMBINE_ALL: $query->andSearch(array($ob)); break; case Ingo_Rule_User::COMBINE_ANY: $query->orSearch(array($ob)); break; } } $base_query->andSearch(array($query)); $indices = $api->search($base_query); if ($indices = array_diff($indices, $ignore_ids)) { if ($rule->stop) { /* If the stop action is set, add these * indices to the list of ids that will be * ignored by subsequent rules. */ $ignore_ids = array_unique($indices + $ignore_ids); } /* Set the flags. */ if ($class !== 'Ingo_Rule_User_Discard') { $flags = array(); if ($rule->flags & Ingo_Rule_User::FLAG_ANSWERED) { $flags[] = '\\answered'; } if ($rule->flags & Ingo_Rule_User::FLAG_DELETED) { $flags[] = '\\deleted'; } if ($rule->flags & Ingo_Rule_User::FLAG_FLAGGED) { $flags[] = '\\flagged'; } if ($rule->flags & Ingo_Rule_User::FLAG_SEEN) { $flags[] = '\\seen'; } if (!empty($flags)) { $api->setMessageFlags($indices, $flags); } } switch ($class) { case 'Ingo_Rule_User_Keep': /* Add these indices to the ignore list. */ $ignore_ids = array_unique($indices + $ignore_ids); break; case 'Ingo_Rule_User_Move': /* We need to grab the envelope first. */ if ($this->_params['show_filter_msg'] && !($fetch = $api->fetchEnvelope($indices))) { continue 2; } $mbox = new Horde_Imap_Client_Mailbox($rule->value); /* Move the messages to the requested mailbox. */ $api->moveMessages($indices, strval($mbox)); /* Display notification message(s). */ if ($this->_params['show_filter_msg']) { foreach ($fetch as $msg) { $envelope = $msg->getEnvelope(); $notification->push(sprintf(_("Filter activity: The message \"%s\" from \"%s\" has been moved to the folder \"%s\"."), !empty($envelope->subject) ? Horde_Mime::decode($envelope->subject) : _("[No Subject]"), !empty($envelope->from) ? strval($envelope->from) : _("[No Sender]"), $mbox), 'horde.message'); } } else { $notification->push(sprintf(_("Filter activity: %s message(s) have been moved to the folder \"%s\"."), count($indices), $mbox), 'horde.message'); } break; case 'Ingo_Rule_User_Discard': /* We need to grab the envelope first. */ if ($this->_params['show_filter_msg'] && !($fetch = $api->fetchEnvelope($indices))) { continue; } /* Delete the messages now. */ $api->deleteMessages($indices); /* Display notification message(s). */ if ($this->_params['show_filter_msg']) { foreach ($fetch as $msg) { $envelope = $msg->getEnvelope(); $notification->push(sprintf(_("Filter activity: The message \"%s\" from \"%s\" has been deleted."), !empty($envelope->subject) ? Horde_Mime::decode($envelope->subject) : _("[No Subject]"), !empty($envelope->from) ? strval($envelope->from) : _("[No Sender]")), 'horde.message'); } } else { $notification->push(sprintf(_("Filter activity: %s message(s) have been deleted."), count($indices)), 'horde.message'); } break; case 'Ingo_Rule_User_MoveKeep': $mbox = new Horde_Imap_Client_Mailbox($rule->value); /* Copy the messages to the requested mailbox. */ $api->copyMessages($indices, strval($mbox)); /* Display notification message(s). */ if ($this->_params['show_filter_msg']) { if (!($fetch = $api->fetchEnvelope($indices))) { continue; } foreach ($fetch as $msg) { $envelope = $msg->getEnvelope(); $notification->push(sprintf(_("Filter activity: The message \"%s\" from \"%s\" has been copied to the folder \"%s\"."), !empty($envelope->subject) ? Horde_Mime::decode($envelope->subject) : _("[No Subject]"), !empty($envelope->from) ? strval($envelope->from) : _("[No Sender]"), $mbox), 'horde.message'); } } else { $notification->push(sprintf(_("Filter activity: %s message(s) have been copied to the folder \"%s\"."), count($indices), $mbox), 'horde.message'); } } } break; } } /* Set cache flag. */ $api->storeCache($change); }
/** * Serialize data. * * @param mixed $data The data to be serialized. * @param mixed $mode The mode of serialization. Can be * either a single mode or array of modes. * If array, will be serialized in the * order provided. * @param mixed $params Any additional parameters the serialization method * requires. * * @return string A serialized string. * @throws Horde_Serialize_Exception */ protected static function _serialize($data, $mode, $params = null) { switch ($mode) { case self::NONE: break; // $params['level'] = Level of compression (default: 3) // $params['workfactor'] = How does compression phase behave when given // worst case, highly repetitive, input data // (default: 30) // $params['level'] = Level of compression (default: 3) // $params['workfactor'] = How does compression phase behave when given // worst case, highly repetitive, input data // (default: 30) case self::BZIP: $data = bzcompress($data, isset($params['level']) ? $params['level'] : 3, isset($params['workfactor']) ? $params['workfactor'] : 30); if (is_integer($data)) { $data = false; } break; case self::WDDX: $data = wddx_serialize_value($data); break; case self::IMAP8: $data = Horde_Mime::quotedPrintableEncode($data); break; case self::IMAPUTF7: $data = Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap(Horde_String::convertCharset($data, 'ISO-8859-1', 'UTF-8')); break; case self::IMAPUTF8: $data = Horde_Mime::decode($data); break; // $params['level'] = Level of compression (default: 3) // $params['level'] = Level of compression (default: 3) case self::GZ_DEFLATE: $data = gzdeflate($data, isset($params['level']) ? $params['level'] : 3); break; case self::BASIC: $data = serialize($data); break; // $params['level'] = Level of compression (default: 3) // $params['level'] = Level of compression (default: 3) case self::GZ_COMPRESS: $data = gzcompress($data, isset($params['level']) ? $params['level'] : 3); break; case self::BASE64: $data = base64_encode($data); break; // $params['level'] = Level of compression (default: 3) // $params['level'] = Level of compression (default: 3) case self::GZ_ENCODE: $data = gzencode($data, isset($params['level']) ? $params['level'] : 3); break; case self::RAW: $data = rawurlencode($data); break; case self::URL: $data = urlencode($data); break; // $params = Source character set // $params = Source character set case self::UTF7: $data = Horde_String::convertCharset($data, $params, 'UTF-7'); break; // $params = Source character set // $params = Source character set case self::UTF7_BASIC: $data = self::serialize($data, array(self::UTF7, self::BASIC), $params); break; case self::JSON: $tmp = json_encode($data); /* Basic error handling attempts. * TODO: JSON_ERROR_UTF8 = 5; available as of PHP 5.3.3 */ if (json_last_error() === 5) { $data = json_encode(Horde_String::convertCharset($data, $params, 'UTF-8', true)); } else { $data = $tmp; } break; case self::LZF: $data = lzf_compress($data); break; } if ($data === false) { throw new Horde_Serialize_Exception('Serialization failed.'); } return $data; }
/** * Recursively parse BODYSTRUCTURE data from a FETCH return (see * RFC 3501 [7.4.2]). * * @param Horde_Imap_Client_Tokenize $data Data returned from the server. * * @return Horde_Mime_Part Mime part object. */ protected function _parseBodystructure(Horde_Imap_Client_Tokenize $data) { $ob = new Horde_Mime_Part(); // If index 0 is an array, this is a multipart part. if (($entry = $data->next()) === true) { do { $ob->addPart($this->_parseBodystructure($data)); } while (($entry = $data->next()) === true); // The subpart type. $ob->setType('multipart/' . $entry); // After the subtype is further extension information. This // information MAY appear for BODYSTRUCTURE requests. // This is parameter information. if (($tmp = $data->next()) === false) { return $ob; } elseif ($tmp === true) { foreach ($this->_parseStructureParams($data, 'content-type') as $key => $val) { $ob->setContentTypeParameter($key, $val); } } } else { $ob->setType($entry . '/' . $data->next()); if ($data->next() === true) { foreach ($this->_parseStructureParams($data, 'content-type') as $key => $val) { $ob->setContentTypeParameter($key, $val); } } if (!is_null($tmp = $data->next())) { $ob->setContentId($tmp); } if (!is_null($tmp = $data->next())) { $ob->setDescription(Horde_Mime::decode($tmp)); } if (!is_null($tmp = $data->next())) { $ob->setTransferEncoding($tmp); } $ob->setBytes($data->next()); // If the type is 'message/rfc822' or 'text/*', several extra // fields are included switch ($ob->getPrimaryType()) { case 'message': if ($ob->getSubType() == 'rfc822') { if ($data->next() === true) { // Ignore: envelope $data->flushIterator(false); } if ($data->next() === true) { $ob->addPart($this->_parseBodystructure($data)); } $data->next(); // Ignore: lines } break; case 'text': $data->next(); // Ignore: lines break; } // After the subtype is further extension information. This // information MAY appear for BODYSTRUCTURE requests. // Ignore: MD5 if ($data->next() === false) { return $ob; } } // This is disposition information if (($tmp = $data->next()) === false) { return $ob; } elseif ($tmp === true) { $ob->setDisposition($data->next()); if ($data->next() === true) { foreach ($this->_parseStructureParams($data, 'content-disposition') as $key => $val) { $ob->setDispositionParameter($key, $val); } } $data->next(); } // This is language information. It is either a single value or a list // of values. if (($tmp = $data->next()) === false) { return $ob; } elseif (!is_null($tmp)) { $ob->setLanguage($tmp === true ? $data->flushIterator() : $tmp); } // Ignore location (RFC 2557) and consume closing paren. $data->flushIterator(false); return $ob; }
/** * Parse the output from imap_fetchstructure() into a MIME Part object. * * @param object $data Data from imap_fetchstructure(). * * @return Horde_Mime_Part A MIME Part object. */ protected function _parseStructure($data) { $ob = new Horde_Mime_Part(); $ob->setType($this->_mimeTypes[$data->type] . '/' . ($data->ifsubtype ? strtolower($data->subtype) : Horde_Mime_Part::UNKNOWN)); // Optional for multipart-parts, required for all others if ($data->ifparameters) { $params = array(); foreach ($data->parameters as $val) { $params[$val->attribute] = $val->value; } $params = Horde_Mime::decodeParam('content-type', $params); foreach ($params['params'] as $key => $val) { $ob->setContentTypeParameter($key, $val); } } // Optional entries. 'location' and 'language' not supported if ($data->ifdisposition) { $ob->setDisposition($data->disposition); if ($data->ifdparameters) { $dparams = array(); foreach ($data->dparameters as $val) { $dparams[$val->attribute] = $val->value; } $dparams = Horde_Mime::decodeParam('content-disposition', $dparams); foreach ($dparams['params'] as $key => $val) { $ob->setDispositionParameter($key, $val); } } } if ($ob->getPrimaryType() == 'multipart') { // multipart/* specific entries foreach ($data->parts as $val) { $ob->addPart($this->_parseStructure($val)); } } else { // Required options if ($data->ifid) { $ob->setContentId($data->id); } if ($data->ifdescription) { $ob->setDescription(Horde_Mime::decode($data->description)); } $ob->setTransferEncoding($this->_mimeEncodings[$data->encoding]); $ob->setBytes($data->bytes); if ($ob->getType() == 'message/rfc822') { $ob->addPart($this->_parseStructure(reset($data->parts))); } } return $ob; }