diff --git a/admin/tool/messageinbound/classes/manager.php b/admin/tool/messageinbound/classes/manager.php index c42d87b462d..4fae00918c0 100644 --- a/admin/tool/messageinbound/classes/manager.php +++ b/admin/tool/messageinbound/classes/manager.php @@ -24,8 +24,6 @@ namespace tool_messageinbound; -defined('MOODLE_INTERNAL') || die(); - /** * Mail Pickup Manager. * @@ -65,7 +63,7 @@ class manager { protected $imapnamespace = null; /** - * @var \Horde_Imap_Client_Socket A reference to the IMAP client. + * @var \rcube_imap_generic A reference to the IMAP client. */ protected $client = null; @@ -79,12 +77,24 @@ class manager { */ protected $currentmessagedata = null; + /** + * Mail Pickup Manager. + */ + public function __construct() { + // Load dependencies. + $this->load_dependencies(); + } + /** * Retrieve the connection to the IMAP client. * + * @param string $mailbox The mailbox to connect to. + * * @return bool Whether a connection was successfully established. */ - protected function get_imap_client() { + protected function get_imap_client( + string $mailbox = self::MAILBOX, + ): bool { global $CFG; if (!\core\message\inbound\manager::is_enabled()) { @@ -95,65 +105,74 @@ class manager { mtrace("Connecting to {$CFG->messageinbound_host} as {$CFG->messageinbound_hostuser}..."); - $configuration = array( + $configuration = [ 'username' => $CFG->messageinbound_hostuser, 'password' => $CFG->messageinbound_hostpass, 'hostspec' => $CFG->messageinbound_host, - 'secure' => $CFG->messageinbound_hostssl, - 'debug' => empty($CFG->debugimap) ? null : fopen('php://stderr', 'w'), - ); + 'options' => [ + 'ssl_mode' => strtolower($CFG->messageinbound_hostssl), + 'auth_type' => 'CHECK', + ], + ]; if (strpos($configuration['hostspec'], ':')) { $hostdata = explode(':', $configuration['hostspec']); if (count($hostdata) === 2) { // A hostname in the format hostname:port has been provided. $configuration['hostspec'] = $hostdata[0]; - $configuration['port'] = $hostdata[1]; + $configuration['options']['port'] = $hostdata[1]; } } // XOAUTH2. - if ($CFG->messageinbound_hostoauth != '') { + if (isset($CFG->messageinbound_hostoauth) && $CFG->messageinbound_hostoauth != '') { // Get the issuer. $issuer = \core\oauth2\api::get_issuer($CFG->messageinbound_hostoauth); // Validate the issuer and check if it is enabled or not. if ($issuer && $issuer->get('enabled')) { // Get the OAuth Client. if ($oauthclient = \core\oauth2\api::get_system_oauth_client($issuer)) { - $xoauth2token = new \Horde_Imap_Client_Password_Xoauth2( - $configuration['username'], - $oauthclient->get_accesstoken()->token - ); - $configuration['xoauth2_token'] = $xoauth2token; - // Password is not necessary when using OAuth2 but Horde still needs it. We just set a random string here. - $configuration['password'] = random_string(64); + $configuration['password'] = 'Bearer ' . $oauthclient->get_accesstoken()->token; + $configuration['options']['auth_type'] = 'XOAUTH2'; } } } - $this->client = new \Horde_Imap_Client_Socket($configuration); + $this->client = new \rcube_imap_generic(); + if (!empty($CFG->debugimap)) { + $this->client->setDebug(debug: true); + } + $success = $this->client->connect( + host: $configuration['hostspec'], + user: $configuration['username'], + password: $configuration['password'], + options: $configuration['options'], + ); - try { - $this->client->login(); + if ($success) { mtrace("Connection established."); // Ensure that mailboxes exist. $this->ensure_mailboxes_exist(); - + // Select mailbox. + $this->client->select(mailbox: $mailbox); return true; - - } catch (\Horde_Imap_Client_Exception $e) { - $message = $e->getMessage(); - throw new \moodle_exception('imapconnectfailure', 'tool_messageinbound', '', null, $message); + } else { + throw new \moodle_exception('imapconnectfailure', 'tool_messageinbound', '', null, 'Could not connect to IMAP server.'); } } /** * Shutdown and close the connection to the IMAP client. */ - protected function close_connection() { + protected function close_connection(): void { if ($this->client) { - $this->client->close(); + // Close the connection and return to authenticated state. + $isclosed = $this->client->close(); + if ($isclosed) { + // Connection was closed unsuccessfully. Send the LOGOUT command and close the socket. + $this->client->closeConnection(); + } } $this->client = null; } @@ -163,12 +182,17 @@ class manager { * * @return string */ - protected function get_confirmation_folder() { - + protected function get_confirmation_folder(): string { if ($this->imapnamespace === null) { - if ($this->client->queryCapability('NAMESPACE')) { - $namespaces = $this->client->getNamespaces(array(), array('ob_return' => true)); - $this->imapnamespace = $namespaces->getNamespace('INBOX'); + $namespaces = $this->client->getNamespace(); + if ($namespaces != $this->client::ERROR_BAD && is_array($namespaces)) { + $nspersonal = reset($namespaces['personal']); + if (is_array($nspersonal) && !empty($nspersonal[0])) { + // Personal namespace is an array, the first part is the name, the second part is the delimiter. + $this->imapnamespace = $nspersonal[0] . $nspersonal[1]; + } else { + $this->imapnamespace = ''; + } } else { $this->imapnamespace = ''; } @@ -178,17 +202,15 @@ class manager { } /** - * Get the current mailbox information. + * Get the current mailbox name. * - * @return \Horde_Imap_Client_Mailbox + * @return string The current mailbox name. * @throws \core\message\inbound\processing_failed_exception if the mailbox could not be opened. */ - protected function get_mailbox() { + protected function get_mailbox(): string { // Get the current mailbox. - $mailbox = $this->client->currentMailbox(); - - if (isset($mailbox['mailbox'])) { - return $mailbox['mailbox']; + if ($this->client->selected) { + return $this->client->selected; } else { throw new \core\message\inbound\processing_failed_exception('couldnotopenmailbox', 'tool_messageinbound'); } @@ -199,30 +221,30 @@ class manager { * * @return bool */ - public function pickup_messages() { + public function pickup_messages(): bool { if (!$this->get_imap_client()) { return false; } // Restrict results to messages which are unseen, and have not been flagged. - $search = new \Horde_Imap_Client_Search_Query(); - $search->flag(self::MESSAGE_SEEN, false); - $search->flag(self::MESSAGE_FLAGGED, false); mtrace("Searching for Unseen, Unflagged email in the folder '" . self::MAILBOX . "'"); - $results = $this->client->search(self::MAILBOX, $search); + $result = $this->client->search( + mailbox: $this->get_mailbox(), + criteria: 'UNSEEN UNFLAGGED', + return_uid: true, + ); - // We require the envelope data and structure of each message. - $query = new \Horde_Imap_Client_Fetch_Query(); - $query->envelope(); - $query->structure(); + if (empty($result->count())) { + return false; + } + mtrace("Found " . $result->count() . " messages to parse. Parsing..."); // Retrieve the message id. - $messages = $this->client->fetch(self::MAILBOX, $query, array('ids' => $results['match'])); - - mtrace("Found " . $messages->count() . " messages to parse. Parsing..."); + $messages = $result->get(); $this->addressmanager = new \core\message\inbound\address_manager(); - foreach ($messages as $message) { - $this->process_message($message); + foreach ($messages as $messageuid) { + $messageuid = is_numeric($messageuid) ? intval($messageuid) : $messageuid; + $this->process_message(messageuid: $messageuid); } // Close the client connection. @@ -238,39 +260,55 @@ class manager { * @return bool Whether the message was successfully processed. * @throws \core\message\inbound\processing_failed_exception if the message cannot be found. */ - public function process_existing_message(\stdClass $maildata) { + public function process_existing_message( + \stdClass $maildata, + ): bool { // Grab the new IMAP client. - if (!$this->get_imap_client()) { + if (!$this->get_imap_client(mailbox: $this->get_confirmation_folder())) { return false; } - // Build the search. - $search = new \Horde_Imap_Client_Search_Query(); // When dealing with Inbound Message messages, we mark them as flagged and seen. Restrict the search to those criterion. - $search->flag(self::MESSAGE_SEEN, true); - $search->flag(self::MESSAGE_FLAGGED, true); mtrace("Searching for a Seen, Flagged message in the folder '" . $this->get_confirmation_folder() . "'"); - // Match the message ID. - $search->headerText('message-id', $maildata->messageid); - $search->headerText('to', $maildata->address); + // Build the search. + $result = $this->client->search( + mailbox: $this->get_mailbox(), + criteria: 'SEEN FLAGGED TO "' . $maildata->address . '"', + return_uid: true, + ); - $results = $this->client->search($this->get_confirmation_folder(), $search); - - // Build the base query. - $query = new \Horde_Imap_Client_Fetch_Query(); - $query->envelope(); - $query->structure(); - - - // Fetch the first message from the client. - $messages = $this->client->fetch($this->get_confirmation_folder(), $query, array('ids' => $results['match'])); $this->addressmanager = new \core\message\inbound\address_manager(); - if ($message = $messages->first()) { + if (!empty($result->count())) { + $messages = $result->get(); + $targetsequence = 0; + mtrace("Found " . $result->count() . " messages to parse. Parsing..."); + foreach ($messages as $messageuid) { + $messageuid = is_numeric($messageuid) ? intval($messageuid) : $messageuid; + $results = $this->client->fetch( + mailbox: $this->get_mailbox(), + message_set: $messageuid, + is_uid: true, + query_items: [ + 'BODY.PEEK[HEADER.FIELDS (Message-ID)]', + ], + ); + $messagedata = reset($results); + // Match the message id. + if (htmlentities($messagedata->get('Message-ID', false)) == $maildata->messageid) { + // Found the message. + $targetsequence = $messageuid; + break; + } + } mtrace("--> Found the message. Passing back to the pickup system."); // Process the message. - $this->process_message($message, true, true); + $this->process_message( + messageuid: $targetsequence, + viewreadmessages: true, + skipsenderverification: true, + ); // Close the client connection. $this->close_connection(); @@ -291,39 +329,46 @@ class manager { * * @return bool Whether tidying occurred successfully. */ - public function tidy_old_messages() { + public function tidy_old_messages(): bool { // Grab the new IMAP client. - if (!$this->get_imap_client()) { + if (!$this->get_imap_client(mailbox: $this->get_confirmation_folder())) { return false; } // Open the mailbox. mtrace("Searching for messages older than 24 hours in the '" . $this->get_confirmation_folder() . "' folder."); - $this->client->openMailbox($this->get_confirmation_folder()); - - $mailbox = $this->get_mailbox(); - - // Build the search. - $search = new \Horde_Imap_Client_Search_Query(); // Delete messages older than 24 hours old. - $search->intervalSearch(DAYSECS, \Horde_Imap_Client_Search_Query::INTERVAL_OLDER); - - $results = $this->client->search($mailbox, $search); - - // Build the base query. - $query = new \Horde_Imap_Client_Fetch_Query(); - $query->envelope(); + $date = date( + format: 'Y-m-d', + timestamp: time() - DAYSECS + ); // Retrieve the messages and mark them for removal. - $messages = $this->client->fetch($mailbox, $query, array('ids' => $results['match'])); - mtrace("Found " . $messages->count() . " messages for removal."); - foreach ($messages as $message) { - $this->add_flag_to_message($message->getUid(), self::MESSAGE_DELETED); + $result = $this->client->search( + mailbox: $this->get_mailbox(), + criteria: 'BEFORE "' . $date . '"', + return_uid: true, + ); + + if (empty($result->count())) { + $this->close_connection(); + return false; + } + + mtrace("Found " . $result->count() . " messages for removal."); + $messages = $result->get(); + foreach ($messages as $messageuid) { + $messageuid = is_numeric($messageuid) ? intval($messageuid) : $messageuid; + $this->add_flag_to_message( + messageuid: $messageuid, + flag: self::MESSAGE_DELETED + ); } mtrace("Finished removing messages."); + $this->close_connection(); return true; @@ -342,26 +387,27 @@ class manager { /** * Process a message and pass it through the Inbound Message handling systems. * - * @param \Horde_Imap_Client_Data_Fetch $message The message to process + * @param int $messageuid The message uid to process * @param bool $viewreadmessages Whether to also look at messages which have been marked as read * @param bool $skipsenderverification Whether to skip the sender verification stage */ public function process_message( - \Horde_Imap_Client_Data_Fetch $message, - $viewreadmessages = false, - $skipsenderverification = false) { + int $messageuid, + bool $viewreadmessages = false, + bool $skipsenderverification = false, + ): void { global $USER; - // We use the Client IDs several times - store them here. - $messageid = new \Horde_Imap_Client_Ids($message->getUid()); - - mtrace("- Parsing message " . $messageid); + mtrace("- Parsing message " . $messageuid); // First flag this message to prevent another running hitting this message while we look at the headers. - $this->add_flag_to_message($messageid, self::MESSAGE_FLAGGED); + $this->add_flag_to_message( + messageuid: $messageuid, + flag: self::MESSAGE_FLAGGED, + ); - if ($this->is_bulk_message($message, $messageid)) { - mtrace("- The message has a bulk header set. This is likely an auto-generated reply - discarding."); + if ($this->is_bulk_message(messageuid: $messageuid)) { + mtrace("- The message " . $messageuid . " has a bulk header set. This is likely an auto-generated reply - discarding."); return; } @@ -369,8 +415,17 @@ class manager { // messages, as \core\cron::setup_user is called multiple times. $originaluser = $USER; - $envelope = $message->getEnvelope(); - $recipients = $envelope->to->bare_addresses; + $envelope = $this->client->fetch( + mailbox: $this->get_mailbox(), + message_set: $messageuid, + is_uid: true, + query_items: [ + 'BODY.PEEK[HEADER.FIELDS (SUBJECT FROM TO)]', + 'ENVELOPE', + ], + ); + $envelope = array_shift($envelope); + $recipients = $this->get_address_from_envelope(addresslist: $envelope->envelope[5]); foreach ($recipients as $recipient) { if (!\core\message\inbound\address_manager::is_correct_format($recipient)) { // Message did not contain a subaddress. @@ -379,7 +434,7 @@ class manager { } // Message contained a match. - $senders = $message->getEnvelope()->from->bare_addresses; + $senders = $this->get_address_from_envelope(addresslist: $envelope->envelope[2]); if (count($senders) !== 1) { mtrace("- Received multiple senders. Only the first sender will be used."); } @@ -389,21 +444,24 @@ class manager { mtrace("-- From:\t" . $sender); mtrace("-- Recipient:\t" . $recipient); - // Grab messagedata including flags. - $query = new \Horde_Imap_Client_Fetch_Query(); - $query->structure(); - $messagedata = $this->client->fetch($this->get_mailbox(), $query, array( - 'ids' => $messageid, - ))->first(); - - if (!$viewreadmessages && $this->message_has_flag($messageid, self::MESSAGE_SEEN)) { + // Check whether this message has already been processed. + if ( + !$viewreadmessages && + $this->message_has_flag( + messageuid: $messageuid, + flag: self::MESSAGE_SEEN, + ) + ) { // Something else has already seen this message. Skip it now. mtrace("-- Skipping the message - it has been marked as seen - perhaps by another process."); continue; } // Mark it as read to lock the message. - $this->add_flag_to_message($messageid, self::MESSAGE_SEEN); + $this->add_flag_to_message( + messageuid: $messageuid, + flag: self::MESSAGE_SEEN, + ); // Now pass it through the Inbound Message processor. $status = $this->addressmanager->process_envelope($recipient, $sender); @@ -412,19 +470,25 @@ class manager { // The handler is disabled. mtrace("-- Skipped message - Handler is disabled. Fail code {$status}"); // In order to handle the user error, we need more information about the message being failed. - $this->process_message_data($envelope, $messagedata, $messageid); + $this->process_message_data( + envelope: $envelope, + messageuid: $messageuid, + ); $this->inform_user_of_error(get_string('handlerdisabled', 'tool_messageinbound', $this->currentmessagedata)); return; } // Check the validation status early. No point processing garbage messages, but we do need to process it // for some validation failure types. - if (!$this->passes_key_validation($status, $messageid)) { + if (!$this->passes_key_validation(status: $status)) { // None of the above validation failures were found. Skip this message. mtrace("-- Skipped message - it does not appear to relate to a Inbound Message pickup. Fail code {$status}"); // Remove the seen flag from the message as there may be multiple recipients. - $this->remove_flag_from_message($messageid, self::MESSAGE_SEEN); + $this->remove_flag_from_message( + messageuid: $messageuid, + flag: self::MESSAGE_SEEN, + ); // Skip further processing for this recipient. continue; @@ -437,7 +501,12 @@ class manager { // Process and retrieve the message data for this message. // This includes fetching the full content, as well as all headers, and attachments. - if (!$this->process_message_data($envelope, $messagedata, $messageid)) { + if ( + !$this->process_message_data( + envelope: $envelope, + messageuid: $messageuid, + ) + ) { mtrace("--- Message could not be found on the server. Is another process removing messages?"); return; } @@ -450,7 +519,12 @@ class manager { mtrace("-- Message did not meet validation but is possibly recoverable. Fail code {$status}"); // This is a recoverable error, but requires user input. - if ($this->handle_verification_failure($messageid, $recipient)) { + if ( + $this->handle_verification_failure( + messageuid: $messageuid, + recipient: $recipient, + ) + ) { mtrace("--- Original message retained on mail server and confirmation message sent to user."); } else { mtrace("--- Invalid Recipient Handler - unable to save. Informing the user of the failure."); @@ -465,7 +539,7 @@ class manager { // Add the content and attachment data. mtrace("-- Validation completed. Fetching rest of message content."); - $this->process_message_data_body($messagedata, $messageid); + $this->process_message_data_body(messageuid: $messageuid); // The message processor throws exceptions upon failure. These must be caught and notifications sent to // the user here. @@ -494,7 +568,10 @@ class manager { if ($result) { // Handle message cleanup. Messages are deleted once fully processed. mtrace("-- Marking the message for removal."); - $this->add_flag_to_message($messageid, self::MESSAGE_DELETED); + $this->add_flag_to_message( + messageuid: $messageuid, + flag: self::MESSAGE_DELETED + ); } else { mtrace("-- The Inbound Message processor did not return a success status. Skipping message removal."); } @@ -503,7 +580,7 @@ class manager { mtrace("-- Returning to the original user."); \core\cron::setup_user($originaluser); - mtrace("-- Finished processing " . $message->getUid()); + mtrace("-- Finished processing " . $messageuid); // Skip the outer loop too. The message has already been processed and it could be possible for there to // be two recipients in the envelope which match somehow. @@ -512,33 +589,26 @@ class manager { } /** - * Process a message to retrieve it's header data without body and attachemnts. + * Process a message to retrieve it's header data without body. * - * @param \Horde_Imap_Client_Data_Envelope $envelope The Envelope of the message - * @param \Horde_Imap_Client_Data_Fetch $basemessagedata The structure and part of the message body - * @param string|\Horde_Imap_Client_Ids $messageid The Hore message Uid - * @return \stdClass The current value of the messagedata + * @param \rcube_message_header $envelope The Envelope of the message + * @param int $messageuid The message Uid to process + * @return \stdClass|null The current value of the messagedata */ private function process_message_data( - \Horde_Imap_Client_Data_Envelope $envelope, - \Horde_Imap_Client_Data_Fetch $basemessagedata, - $messageid) { - - // Get the current mailbox. - $mailbox = $this->get_mailbox(); - - // We need the structure at various points below. - $structure = $basemessagedata->getStructure(); - - // Now fetch the rest of the message content. - $query = new \Horde_Imap_Client_Fetch_Query(); - $query->imapDate(); - - // Fetch the message header. - $query->headerText(); - - // Retrieve the message with the above components. - $messagedata = $this->client->fetch($mailbox, $query, array('ids' => $messageid))->first(); + \rcube_message_header $envelope, + int $messageuid, + ): ?\stdClass { + // Retrieve the message with necessary information. + $messages = $this->client->fetch( + mailbox: $this->get_mailbox(), + message_set: $messageuid, + is_uid: true, + query_items: [ + 'BODY.PEEK[HEADER.FIELDS (Message-ID SUBJECT DATE)]', + ], + ); + $messagedata = reset($messages); if (!$messagedata) { // Message was not found! Somehow it has been removed or is no longer returned. @@ -547,12 +617,11 @@ class manager { // The message ID should always be in the first part. $data = new \stdClass(); - $data->messageid = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('Message-ID'); - $data->subject = $envelope->subject; - $data->timestamp = $messagedata->getImapDate()->__toString(); + $data->messageid = htmlentities($messagedata->get('Message-ID', false)); + $data->subject = $messagedata->get('SUBJECT', false); + $data->timestamp = strtotime($messagedata->get('DATE', false)); $data->envelope = $envelope; $data->data = $this->addressmanager->get_data(); - $data->headers = $messagedata->getHeaderText(); $this->currentmessagedata = $data; @@ -562,74 +631,65 @@ class manager { /** * Process a message again to add body and attachment data. * - * @param \Horde_Imap_Client_Data_Fetch $basemessagedata The structure and part of the message body - * @param string|\Horde_Imap_Client_Ids $messageid The Hore message Uid - * @return \stdClass The current value of the messagedata + * @param int $messageuid The message Uid + * @return \stdClass|null The current value of the messagedata */ private function process_message_data_body( - \Horde_Imap_Client_Data_Fetch $basemessagedata, - $messageid) { - global $CFG; - - // Get the current mailbox. - $mailbox = $this->get_mailbox(); - - // We need the structure at various points below. - $structure = $basemessagedata->getStructure(); - - // Now fetch the rest of the message content. - $query = new \Horde_Imap_Client_Fetch_Query(); - $query->fullText(); - - // Fetch all of the message parts too. - $typemap = $structure->contentTypeMap(); - foreach ($typemap as $part => $type) { - // The body of the part - attempt to decode it on the server. - $query->bodyPart($part, array( - 'decode' => true, - 'peek' => true, - )); - $query->bodyPartSize($part); - } - - $messagedata = $this->client->fetch($mailbox, $query, array('ids' => $messageid))->first(); + int $messageuid, + ): ?\stdClass { + $messages = $this->client->fetch( + mailbox: $this->get_mailbox(), + message_set: $messageuid, + is_uid: true, + query_items: [ + 'BODYSTRUCTURE', + ], + ); + $messagedata = reset($messages); + $structure = $messagedata->bodystructure; // Store the data for this message. $contentplain = ''; $contenthtml = ''; - $attachments = array( - 'inline' => array(), - 'attachment' => array(), - ); - - $plainpartid = $structure->findBody('plain'); - $htmlpartid = $structure->findBody('html'); - - foreach ($typemap as $part => $type) { - // Get the message data from the body part, and combine it with the structure to give a fully-formed output. - $stream = $messagedata->getBodyPart($part, true); - $partdata = $structure->getPart($part); - $partdata->setContents($stream, array( - 'usestream' => true, - )); - - if ($part == $plainpartid) { - $contentplain = $this->process_message_part_body($messagedata, $partdata, $part); - - } else if ($part == $htmlpartid) { - $contenthtml = $this->process_message_part_body($messagedata, $partdata, $part); - - } else if ($filename = $partdata->getName($part)) { - if ($attachment = $this->process_message_part_attachment($messagedata, $partdata, $part, $filename)) { - // The disposition should be one of 'attachment', 'inline'. - // If an empty string is provided, default to 'attachment'. - $disposition = $partdata->getDisposition(); - $disposition = $disposition == 'inline' ? 'inline' : 'attachment'; - $attachments[$disposition][] = $attachment; - } + $attachments = [ + 'inline' => [], + 'attachment' => [], + ]; + $parameters = []; + foreach ($structure as $partno => $part) { + if (!is_array($part)) { + continue; } + $section = $partno + 1; - // We don't handle any of the other MIME content at this stage. + // Subpart recursion. + if (is_array($part[0])) { + foreach ($part as $subpartno => $subpart) { + if (!is_array($subpart)) { + continue; + } + $subsection = $subpartno + 1; + $this->process_message_data_body_part( + messageuid: $messageuid, + partstructure: $subpart, + section: $section . '.' . $subsection, + contentplain: $contentplain, + contenthtml: $contenthtml, + attachments: $attachments, + parameters: $parameters, + ); + } + } else { + $this->process_message_data_body_part( + messageuid: $messageuid, + partstructure: $part, + section: $section, + contentplain: $contentplain, + contenthtml: $contenthtml, + attachments: $attachments, + parameters: $parameters, + ); + } } // The message ID should always be in the first part. @@ -641,26 +701,167 @@ class manager { } /** - * Process the messagedata and part data to extract the content of this part. + * Process message data body part. * - * @param \Horde_Imap_Client_Data_Fetch $messagedata The structure and part of the message body - * @param \Horde_Mime_Part $partdata The part data - * @param string $part The part ID - * @return string + * @param int $messageuid Message uid to process. + * @param array $partstructure Body part structure. + * @param string $section Section number. + * @param string $contentplain Plain text content. + * @param string $contenthtml HTML content. + * @param array $attachments Attachments. + * @param array $parameters Parameters. */ - private function process_message_part_body($messagedata, $partdata, $part) { - // This is a content section for the main body. + private function process_message_data_body_part( + int $messageuid, + array $partstructure, + string $section, + string &$contentplain, + string &$contenthtml, + array &$attachments, + array &$parameters, + ): void { + $messages = $this->client->fetch( + mailbox: $this->get_mailbox(), + message_set: $messageuid, + is_uid: true, + query_items: [ + 'BODY[' . $section . ']', + ], + ); + if ($messages) { + $messagedata = reset($messages); - // Get the string version of it. - $content = $messagedata->getBodyPart($part); - if (!$messagedata->getBodyPartDecode($part)) { - // Decode the content. - $partdata->setContents($content); - $content = $partdata->getContents(); + // Parse encoding. + $encoding = array_search( + needle: strtoupper($partstructure[5]), + haystack: utils::get_body_encoding(), + ); + + // Parse subtype. + $subtype = strtoupper($partstructure[1]); + + // Section part may be encoded, even plain text messages, so check everything. + if ($encoding == utils::ENCQUOTEDPRINTABLE) { + $data = quoted_printable_decode($messagedata->bodypart[$section]); + } else if ($encoding == utils::ENCBASE64) { + $data = base64_decode($messagedata->bodypart[$section]); + } else { + $data = $messagedata->bodypart[$section]; + } + + // Parse parameters. + $parameters = $this->process_message_body_structure_parameters( + attributes: $partstructure[2], + parameters: $parameters, + ); + + // Parse content id. + $contentid = ''; + if (!empty($partstructure[3])) { + $contentid = htmlentities($partstructure[3]); + } + + // Parse description. + $description = ''; + if (!empty($partstructure[4])) { + $description = $partstructure[4]; + } + + // Parse size of contents in bytes. + $bytes = intval($partstructure[6]); + + // PLAIN text. + if ($subtype == 'PLAIN') { + $contentplain = $this->process_message_part_body( + bodycontent: $data, + charset: $parameters['CHARSET'], + ); + } + // HTML. + if ($subtype == 'HTML') { + $contenthtml = $this->process_message_part_body( + bodycontent: $data, + charset: $parameters['CHARSET'], + ); + } + // ATTACHMENT. + if (isset($parameters['NAME']) || isset($parameters['FILENAME'])) { + $filename = $parameters['NAME'] ?? $parameters['FILENAME']; + if ( + $attachment = $this->process_message_part_attachment( + filename: $filename, + filecontent: $data, + contentid: $contentid, + filesize: $bytes, + description: $description, + ) + ) { + // Parse disposition. + $disposition = null; + if (is_array($partstructure[8])) { + $disposition = strtolower($partstructure[8][0]); + } + $disposition = $disposition == 'inline' ? 'inline' : 'attachment'; + $attachments[$disposition][] = $attachment; + } + } + } + } + + /** + * Process message data body parameters. + * + * @param array $attributes List of attributes. + * @param array $parameters List of parameters. + * @return array + */ + private function process_message_body_structure_parameters( + array $attributes, + array $parameters, + ): array { + if (empty($attributes)) { + return []; } + $attribute = null; + + foreach ($attributes as $value) { + if (empty($attribute)) { + $attribute = [ + 'attribute' => $value, + 'value' => null, + ]; + } else { + $attribute['value'] = $value; + $parameters[] = (object) $attribute; + $attribute = null; + } + } + + $params = []; + foreach ($parameters as $parameter) { + if (isset($parameter->attribute)) { + $params[$parameter->attribute] = $parameter->value; + } + } + + return $params; + } + + /** + * Process the message body content. + * + * @param string $bodycontent The message body. + * @param string $charset The charset of the message body. + * @return string Processed content. + */ + private function process_message_part_body( + string $bodycontent, + string $charset, + ): string { + // This is a content section for the main body. // Convert the text from the current encoding to UTF8. - $content = \core_text::convert($content, $partdata->getCharset()); + $content = \core_text::convert($bodycontent, $charset); // Fix any invalid UTF8 characters. // Note: XSS cleaning is not the responsibility of this code. It occurs immediately before display when @@ -673,36 +874,32 @@ class manager { /** * Process a message again to add body and attachment data. * - * @param \Horde_Imap_Client_Data_Fetch $messagedata The structure and part of the message body - * @param \Horde_Mime_Part $partdata The part data - * @param string $part The part ID. - * @param string $filename The filename of the attachment + * @param string $filename The filename of the attachment. + * @param string $filecontent The content of the attachment. + * @param string $contentid The content id of the attachment. + * @param int $filesize The size of the attachment. + * @param string $description The description of the attachment. * @return \stdClass - * @throws \core\message\inbound\processing_failed_exception If the attachment can't be saved to disk. */ - private function process_message_part_attachment($messagedata, $partdata, $part, $filename) { + private function process_message_part_attachment( + string $filename, + string $filecontent, + string $contentid, + int $filesize, + string $description = '', + ): \stdClass { global $CFG; // If a filename is present, assume that this part is an attachment. $attachment = new \stdClass(); - $attachment->filename = $filename; - $attachment->type = $partdata->getType(); - $attachment->content = $partdata->getContents(); - $attachment->charset = $partdata->getCharset(); - $attachment->description = $partdata->getDescription(); - $attachment->contentid = $partdata->getContentId(); - $attachment->filesize = $partdata->getBytes(); + $attachment->filename = $filename; + $attachment->content = $filecontent; + $attachment->description = $description; + $attachment->contentid = $contentid; + $attachment->filesize = $filesize; if (!empty($CFG->antiviruses)) { - mtrace("--> Attempting virus scan of '{$attachment->filename}'"); - // Perform a virus scan now. - try { - \core\antivirus\manager::scan_data($attachment->content); - } catch (\core\antivirus\scanner_exception $e) { - mtrace("--> A virus was found in the attachment '{$attachment->filename}'."); - $this->inform_attachment_virus(); - return; - } + // Virus scanning is removed and will be brought back by MDL-50434. } return $attachment; @@ -711,11 +908,12 @@ class manager { /** * Check whether the key provided is valid. * - * @param bool $status - * @param mixed $messageid The Hore message Uid + * @param int $status The status to validate. * @return bool */ - private function passes_key_validation($status, $messageid) { + private function passes_key_validation( + int $status, + ): bool { // The validation result is tested in a bitwise operation. if (( $status & ~ \core\message\inbound\address_manager::VALIDATION_SUCCESS @@ -733,114 +931,128 @@ class manager { /** * Add the specified flag to the message. * - * @param mixed $messageid + * @param int $messageuid Message uid to process * @param string $flag The flag to add */ - private function add_flag_to_message($messageid, $flag) { - // Get the current mailbox. - $mailbox = $this->get_mailbox(); - - // Mark it as read to lock the message. - $this->client->store($mailbox, array( - 'ids' => new \Horde_Imap_Client_Ids($messageid), - 'add' => $flag, - )); + private function add_flag_to_message( + int $messageuid, + string $flag, + ): void { + // Add flag to the message. + $this->client->flag( + mailbox: $this->get_mailbox(), + messages: $messageuid, + flag: strtoupper(substr($flag, 1)), + ); } /** * Remove the specified flag from the message. * - * @param mixed $messageid + * @param int $messageuid Message uid to process * @param string $flag The flag to remove */ - private function remove_flag_from_message($messageid, $flag) { - // Get the current mailbox. - $mailbox = $this->get_mailbox(); - - // Mark it as read to lock the message. - $this->client->store($mailbox, array( - 'ids' => $messageid, - 'delete' => $flag, - )); + private function remove_flag_from_message( + int $messageuid, + string $flag, + ): void { + // Remove the flag from the message. + $this->client->unflag( + mailbox: $this->get_mailbox(), + messages: $messageuid, + flag: strtoupper(substr($flag, 1)), + ); } /** * Check whether the message has the specified flag * - * @param mixed $messageid - * @param string $flag The flag to check - * @return bool + * @param int $messageuid Message uid to check. + * @param string $flag The flag to check. + * @return bool True if the message has the flag, false otherwise. */ - private function message_has_flag($messageid, $flag) { - // Get the current mailbox. - $mailbox = $this->get_mailbox(); - - // Grab messagedata including flags. - $query = new \Horde_Imap_Client_Fetch_Query(); - $query->flags(); - $query->structure(); - $messagedata = $this->client->fetch($mailbox, $query, array( - 'ids' => $messageid, - ))->first(); - $flags = $messagedata->getFlags(); - - return in_array($flag, $flags); + private function message_has_flag( + int $messageuid, + string $flag, + ): bool { + // Grab the message data with flags. + $messages = $this->client->fetch( + mailbox: $this->get_mailbox(), + message_set: $messageuid, + is_uid: true, + query_items: [ + 'FLAGS', + ], + ); + $messagedata = reset($messages); + $flags = $messagedata->flags; + return array_key_exists( + key: strtoupper(substr($flag, 1)), + array: $flags, + ); } /** * Ensure that all mailboxes exist. */ - private function ensure_mailboxes_exist() { - - $requiredmailboxes = array( + private function ensure_mailboxes_exist(): void { + $requiredmailboxes = [ self::MAILBOX, $this->get_confirmation_folder(), - ); + ]; - $existingmailboxes = $this->client->listMailboxes($requiredmailboxes); + $existingmailboxes = $this->client->listMailboxes( + ref: '', + mailbox: '*', + ); foreach ($requiredmailboxes as $mailbox) { - if (isset($existingmailboxes[$mailbox])) { + if (in_array($mailbox, $existingmailboxes)) { // This mailbox was found. continue; } mtrace("Unable to find the '{$mailbox}' mailbox - creating it."); - $this->client->createMailbox($mailbox); + $this->client->createFolder( + mailbox: $mailbox, + ); } } /** * Attempt to determine whether this message is a bulk message (e.g. automated reply). * - * @param \Horde_Imap_Client_Data_Fetch $message The message to process - * @param string|\Horde_Imap_Client_Ids $messageid The Hore message Uid + * @param int $messageuid The message uid to check * @return boolean */ private function is_bulk_message( - \Horde_Imap_Client_Data_Fetch $message, - $messageid) { - $query = new \Horde_Imap_Client_Fetch_Query(); - $query->headerText(array('peek' => true)); - - $messagedata = $this->client->fetch($this->get_mailbox(), $query, array('ids' => $messageid))->first(); - + int $messageuid, + ): bool { + $messages = $this->client->fetch( + mailbox: $this->get_mailbox(), + message_set: $messageuid, + is_uid: true, + query_items: [ + 'BODY.PEEK[HEADER.FIELDS (Precedence X-Autoreply X-Autorespond Auto-Submitted)]', + ], + ); + $headerinfo = reset($messages); // Assume that this message is not bulk to begin with. $isbulk = false; // An auto-reply may itself include the Bulk Precedence. - $precedence = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('Precedence'); + $precedence = $headerinfo->get('Precedence', false); $isbulk = $isbulk || strtolower($precedence ?? '') == 'bulk'; // If the X-Autoreply header is set, and not 'no', then this is an automatic reply. - $autoreply = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('X-Autoreply'); + $autoreply = $headerinfo->get('X-Autoreply', false); $isbulk = $isbulk || ($autoreply && $autoreply != 'no'); // If the X-Autorespond header is set, and not 'no', then this is an automatic response. - $autorespond = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('X-Autorespond'); + $autorespond = $headerinfo->get('X-Autorespond', false); $isbulk = $isbulk || ($autorespond && $autorespond != 'no'); // If the Auto-Submitted header is set, and not 'no', then this is a non-human response. - $autosubmitted = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('Auto-Submitted'); + $autosubmitted = $headerinfo->get('Auto-Submitted', false); $isbulk = $isbulk || ($autosubmitted && $autosubmitted != 'no'); return $isbulk; @@ -897,30 +1109,32 @@ class manager { * stored. The message includes a verification link and reply-to address which is handled by the * invalid_recipient_handler. * - * @param \Horde_Imap_Client_Ids $messageids + * @param int $messageuid The message uid to process. * @param string $recipient The message recipient * @return bool */ private function handle_verification_failure( - \Horde_Imap_Client_Ids $messageids, - $recipient) { + int $messageuid, + string $recipient, + ): bool { global $DB, $USER; - if (!$messageid = $this->currentmessagedata->messageid) { + $messageid = $this->get_message_sequence_from_uid($messageuid); + if ($messageid == $this->currentmessagedata->messageid) { mtrace("---> Warning: Unable to determine the Message-ID of the message."); return false; } // Move the message into a new mailbox. - $this->client->copy(self::MAILBOX, $this->get_confirmation_folder(), array( - 'create' => true, - 'ids' => $messageids, - 'move' => true, - )); + $this->client->move( + messages: $messageuid, + from: $this->get_mailbox(), + to: $this->get_confirmation_folder(), + ); // Store the data from the failed message in the associated table. $record = new \stdClass(); - $record->messageid = $messageid; + $record->messageid = $messageuid; $record->userid = $USER->id; $record->address = $recipient; $record->timecreated = time(); @@ -938,7 +1152,7 @@ class manager { $userfrom = clone $USER; $userfrom->customheaders = array(); // Adding the In-Reply-To header ensures that it is seen as a reply. - $userfrom->customheaders[] = 'In-Reply-To: ' . $messageid; + $userfrom->customheaders[] = 'In-Reply-To: ' . $messageuid; // The message will be sent from the intended user. $eventdata->courseid = SITEID; @@ -1077,4 +1291,63 @@ class manager { return $subject; } + + /** + * Parse the address from the envelope. + * + * @param array $addresslist List of email addresses to parse. + * @return array|null List of parsed email addresses. + */ + protected function get_address_from_envelope(array $addresslist): array|null { + if (empty($addresslist)) { + return null; + } + + $parsedaddressentry = []; + foreach ($addresslist as $addressentry) { + $parsedaddressentry[] = "{$addressentry[2]}@{$addressentry[3]}"; + } + + return $parsedaddressentry; + } + + /** + * Get the message sequence number from the message uid. + * + * @param int $messageuid The message uid to process. + * @return int The message sequence number. + */ + protected function get_message_sequence_from_uid( + int $messageuid, + ): int { + $messages = $this->client->fetch( + mailbox: $this->get_mailbox(), + message_set: $messageuid, + is_uid: true, + query_items: [ + 'SEQUENCE', + ], + ); + $messagedata = reset($messages); + return $messagedata->sequence; + } + + /** + * We use Roundcube Framework to receive the emails. + * This method will load the required dependencies. + */ + protected function load_dependencies(): void { + global $CFG; + $dependencies = [ + 'rcube_charset.php', + 'rcube_imap_generic.php', + 'rcube_message_header.php', + 'rcube_mime.php', + 'rcube_result_index.php', + 'rcube_result_thread.php', + 'rcube_utils.php', + ]; + + array_map(fn($file) => require_once("$CFG->dirroot/$CFG->admin/tool/messageinbound/roundcube/{$file}"), $dependencies); + } } diff --git a/admin/tool/messageinbound/classes/utils.php b/admin/tool/messageinbound/classes/utils.php new file mode 100644 index 00000000000..2caf1d6efe0 --- /dev/null +++ b/admin/tool/messageinbound/classes/utils.php @@ -0,0 +1,56 @@ +. + +namespace tool_messageinbound; + +/** + * The Mail Pickup Utils. + * + * @package tool_messageinbound + * @copyright 2023 Huong Nguyen + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class utils { + + /** @var int Encoding type: 7 bit SMTP semantic data. */ + const ENC7BIT = 0; + /** @var int Encoding type: 8 bit SMTP semantic data. */ + const ENC8BIT = 1; + /** @var int Encoding type: 8 bit binary data. */ + const ENCBINARY = 2; + /** @var int Encoding type: BASE64 encoded data. */ + const ENCBASE64 = 3; + /** @var int Encoding type: Human-readable 8-as-7 bit data. */ + const ENCQUOTEDPRINTABLE = 4; + /** @var int Encoding type: Unknown. */ + const ENCOTHER = 5; + + /** + * Get body content encoding. + * + * @return string[] List of body content encoding. + */ + public static function get_body_encoding(): array { + return [ + self::ENC7BIT => '7BIT', + self::ENC8BIT => '8BIT', + self::ENCBINARY => 'BINARY', + self::ENCBASE64 => 'BASE64', + self::ENCQUOTEDPRINTABLE => 'QUOTED-PRINTABLE', + self::ENCOTHER => 'X-UNKNOWN', + ]; + } +} diff --git a/admin/tool/messageinbound/roundcube/rcube_charset.php b/admin/tool/messageinbound/roundcube/rcube_charset.php new file mode 100644 index 00000000000..6b67d73ba39 --- /dev/null +++ b/admin/tool/messageinbound/roundcube/rcube_charset.php @@ -0,0 +1,615 @@ + | + | | + | Licensed under the GNU General Public License version 3 or | + | any later version with exceptions for skins & plugins. | + | See the README file for a full license statement. | + | | + | PURPOSE: | + | Provide charset conversion functionality | + +-----------------------------------------------------------------------+ + | Author: Thomas Bruederli | + | Author: Aleksander Machniak | + | Author: Edmund Grimley Evans | + +-----------------------------------------------------------------------+ +*/ + +/** + * Character sets conversion functionality + * + * @package Framework + * @subpackage Core + */ +class rcube_charset +{ + /** + * Character set aliases (some of them from HTML5 spec.) + * + * @var array + */ + static public $aliases = [ + 'USASCII' => 'WINDOWS-1252', + 'ANSIX31101983' => 'WINDOWS-1252', + 'ANSIX341968' => 'WINDOWS-1252', + 'UNKNOWN8BIT' => 'ISO-8859-15', + 'UNKNOWN' => 'ISO-8859-15', + 'USERDEFINED' => 'ISO-8859-15', + 'KSC56011987' => 'EUC-KR', + 'GB2312' => 'GBK', + 'GB231280' => 'GBK', + 'UNICODE' => 'UTF-8', + 'UTF7IMAP' => 'UTF7-IMAP', + 'TIS620' => 'WINDOWS-874', + 'ISO88599' => 'WINDOWS-1254', + 'ISO885911' => 'WINDOWS-874', + 'MACROMAN' => 'MACINTOSH', + '77' => 'MAC', + '128' => 'SHIFT-JIS', + '129' => 'CP949', + '130' => 'CP1361', + '134' => 'GBK', + '136' => 'BIG5', + '161' => 'WINDOWS-1253', + '162' => 'WINDOWS-1254', + '163' => 'WINDOWS-1258', + '177' => 'WINDOWS-1255', + '178' => 'WINDOWS-1256', + '186' => 'WINDOWS-1257', + '204' => 'WINDOWS-1251', + '222' => 'WINDOWS-874', + '238' => 'WINDOWS-1250', + 'MS950' => 'CP950', + 'WINDOWS31J' => 'CP932', + 'WINDOWS949' => 'UHC', + 'WINDOWS1257' => 'ISO-8859-13', + 'ISO2022JP' => 'ISO-2022-JP-MS', + ]; + + /** + * Windows codepages + * + * @var array + */ + static public $windows_codepages = [ + 37 => 'IBM037', // IBM EBCDIC US-Canada + 437 => 'IBM437', // OEM United States + 500 => 'IBM500', // IBM EBCDIC International + 708 => 'ASMO-708', // Arabic (ASMO 708) + 720 => 'DOS-720', // Arabic (Transparent ASMO); Arabic (DOS) + 737 => 'IBM737', // OEM Greek (formerly 437G); Greek (DOS) + 775 => 'IBM775', // OEM Baltic; Baltic (DOS) + 850 => 'IBM850', // OEM Multilingual Latin 1; Western European (DOS) + 852 => 'IBM852', // OEM Latin 2; Central European (DOS) + 855 => 'IBM855', // OEM Cyrillic (primarily Russian) + 857 => 'IBM857', // OEM Turkish; Turkish (DOS) + 858 => 'IBM00858', // OEM Multilingual Latin 1 + Euro symbol + 860 => 'IBM860', // OEM Portuguese; Portuguese (DOS) + 861 => 'IBM861', // OEM Icelandic; Icelandic (DOS) + 862 => 'DOS-862', // OEM Hebrew; Hebrew (DOS) + 863 => 'IBM863', // OEM French Canadian; French Canadian (DOS) + 864 => 'IBM864', // OEM Arabic; Arabic (864) + 865 => 'IBM865', // OEM Nordic; Nordic (DOS) + 866 => 'cp866', // OEM Russian; Cyrillic (DOS) + 869 => 'IBM869', // OEM Modern Greek; Greek, Modern (DOS) + 870 => 'IBM870', // IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 + 874 => 'windows-874', // ANSI/OEM Thai (ISO 8859-11); Thai (Windows) + 875 => 'cp875', // IBM EBCDIC Greek Modern + 932 => 'shift_jis', // ANSI/OEM Japanese; Japanese (Shift-JIS) + 936 => 'gb2312', // ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) + 950 => 'big5', // ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) + 1026 => 'IBM1026', // IBM EBCDIC Turkish (Latin 5) + 1047 => 'IBM01047', // IBM EBCDIC Latin 1/Open System + 1140 => 'IBM01140', // IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) + 1141 => 'IBM01141', // IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) + 1142 => 'IBM01142', // IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) + 1143 => 'IBM01143', // IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) + 1144 => 'IBM01144', // IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) + 1145 => 'IBM01145', // IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) + 1146 => 'IBM01146', // IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) + 1147 => 'IBM01147', // IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) + 1148 => 'IBM01148', // IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) + 1149 => 'IBM01149', // IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) + 1200 => 'UTF-16', // Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications + 1201 => 'UTF-16BE', // Unicode UTF-16, big endian byte order; available only to managed applications + 1250 => 'windows-1250', // ANSI Central European; Central European (Windows) + 1251 => 'windows-1251', // ANSI Cyrillic; Cyrillic (Windows) + 1252 => 'windows-1252', // ANSI Latin 1; Western European (Windows) + 1253 => 'windows-1253', // ANSI Greek; Greek (Windows) + 1254 => 'windows-1254', // ANSI Turkish; Turkish (Windows) + 1255 => 'windows-1255', // ANSI Hebrew; Hebrew (Windows) + 1256 => 'windows-1256', // ANSI Arabic; Arabic (Windows) + 1257 => 'windows-1257', // ANSI Baltic; Baltic (Windows) + 1258 => 'windows-1258', // ANSI/OEM Vietnamese; Vietnamese (Windows) + 10000 => 'macintosh', // MAC Roman; Western European (Mac) + 12000 => 'UTF-32', // Unicode UTF-32, little endian byte order; available only to managed applications + 12001 => 'UTF-32BE', // Unicode UTF-32, big endian byte order; available only to managed applications + 20127 => 'US-ASCII', // US-ASCII (7-bit) + 20273 => 'IBM273', // IBM EBCDIC Germany + 20277 => 'IBM277', // IBM EBCDIC Denmark-Norway + 20278 => 'IBM278', // IBM EBCDIC Finland-Sweden + 20280 => 'IBM280', // IBM EBCDIC Italy + 20284 => 'IBM284', // IBM EBCDIC Latin America-Spain + 20285 => 'IBM285', // IBM EBCDIC United Kingdom + 20290 => 'IBM290', // IBM EBCDIC Japanese Katakana Extended + 20297 => 'IBM297', // IBM EBCDIC France + 20420 => 'IBM420', // IBM EBCDIC Arabic + 20423 => 'IBM423', // IBM EBCDIC Greek + 20424 => 'IBM424', // IBM EBCDIC Hebrew + 20838 => 'IBM-Thai', // IBM EBCDIC Thai + 20866 => 'koi8-r', // Russian (KOI8-R); Cyrillic (KOI8-R) + 20871 => 'IBM871', // IBM EBCDIC Icelandic + 20880 => 'IBM880', // IBM EBCDIC Cyrillic Russian + 20905 => 'IBM905', // IBM EBCDIC Turkish + 20924 => 'IBM00924', // IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) + 20932 => 'EUC-JP', // Japanese (JIS 0208-1990 and 0212-1990) + 20936 => 'cp20936', // Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) + 20949 => 'cp20949', // Korean Wansung + 21025 => 'cp1025', // IBM EBCDIC Cyrillic Serbian-Bulgarian + 21866 => 'koi8-u', // Ukrainian (KOI8-U); Cyrillic (KOI8-U) + 28591 => 'iso-8859-1', // ISO 8859-1 Latin 1; Western European (ISO) + 28592 => 'iso-8859-2', // ISO 8859-2 Central European; Central European (ISO) + 28593 => 'iso-8859-3', // ISO 8859-3 Latin 3 + 28594 => 'iso-8859-4', // ISO 8859-4 Baltic + 28595 => 'iso-8859-5', // ISO 8859-5 Cyrillic + 28596 => 'iso-8859-6', // ISO 8859-6 Arabic + 28597 => 'iso-8859-7', // ISO 8859-7 Greek + 28598 => 'iso-8859-8', // ISO 8859-8 Hebrew; Hebrew (ISO-Visual) + 28599 => 'iso-8859-9', // ISO 8859-9 Turkish + 28603 => 'iso-8859-13', // ISO 8859-13 Estonian + 28605 => 'iso-8859-15', // ISO 8859-15 Latin 9 + 38598 => 'iso-8859-8-i', // ISO 8859-8 Hebrew; Hebrew (ISO-Logical) + 50220 => 'iso-2022-jp', // ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) + 50221 => 'csISO2022JP', // ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) + 50222 => 'iso-2022-jp', // ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) + 50225 => 'iso-2022-kr', // ISO 2022 Korean + 51932 => 'EUC-JP', // EUC Japanese + 51936 => 'EUC-CN', // EUC Simplified Chinese; Chinese Simplified (EUC) + 51949 => 'EUC-KR', // EUC Korean + 52936 => 'hz-gb-2312', // HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) + 54936 => 'GB18030', // Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) + 65000 => 'UTF-7', + 65001 => 'UTF-8', + ]; + + /** + * Validate character set identifier. + * + * @param string $input Character set identifier + * + * @return bool True if valid, False if not valid + */ + public static function is_valid($input) + { + return is_string($input) && preg_match('|^[a-zA-Z0-9_./:#-]{2,32}$|', $input) > 0; + } + + /** + * Parse and validate charset name string. + * Sometimes charset string is malformed, there are also charset aliases, + * but we need strict names for charset conversion (specially utf8 class) + * + * @param string $input Input charset name + * + * @return string The validated charset name + */ + public static function parse_charset($input) + { + static $charsets = []; + + $charset = strtoupper((string) $input); + + if (isset($charsets[$input])) { + return $charsets[$input]; + } + + $charset = preg_replace([ + '/^[^0-9A-Z]+/', // e.g. _ISO-8859-JP$SIO + '/\$.*$/', // e.g. _ISO-8859-JP$SIO + '/UNICODE-1-1-*/', // RFC1641/1642 + '/^X-/', // X- prefix (e.g. X-ROMAN8 => ROMAN8) + '/\*.*$/' // lang code according to RFC 2231.5 + ], '', $charset); + + if ($charset == 'BINARY') { + return $charsets[$input] = null; + } + + // allow A-Z and 0-9 only + $str = preg_replace('/[^A-Z0-9]/', '', $charset); + + $result = $charset; + + if (isset(self::$aliases[$str])) { + $result = self::$aliases[$str]; + } + // UTF + else if (preg_match('/U[A-Z][A-Z](7|8|16|32)(BE|LE)*/', $str, $m)) { + $result = 'UTF-' . $m[1] . (!empty($m[2]) ? $m[2] : ''); + } + // ISO-8859 + else if (preg_match('/ISO8859([0-9]{0,2})/', $str, $m)) { + $iso = 'ISO-8859-' . ($m[1] ?: 1); + // some clients sends windows-1252 text as latin1, + // it is safe to use windows-1252 for all latin1 + $result = $iso == 'ISO-8859-1' ? 'WINDOWS-1252' : $iso; + } + // handle broken charset names e.g. WINDOWS-1250HTTP-EQUIVCONTENT-TYPE + else if (preg_match('/(WIN|WINDOWS)([0-9]+)/', $str, $m)) { + $result = 'WINDOWS-' . $m[2]; + } + // LATIN + else if (preg_match('/LATIN(.*)/', $str, $m)) { + $aliases = ['2' => 2, '3' => 3, '4' => 4, '5' => 9, '6' => 10, + '7' => 13, '8' => 14, '9' => 15, '10' => 16, + 'ARABIC' => 6, 'CYRILLIC' => 5, 'GREEK' => 7, 'GREEK1' => 7, 'HEBREW' => 8 + ]; + + // some clients sends windows-1252 text as latin1, + // it is safe to use windows-1252 for all latin1 + if ($m[1] == 1) { + $result = 'WINDOWS-1252'; + } + // we need ISO labels + else if (!empty($aliases[$m[1]])) { + $result = 'ISO-8859-'.$aliases[$m[1]]; + } + } + + $charsets[$input] = $result; + + return $result; + } + + /** + * Convert a string from one charset to another. + * + * @param string $str Input string + * @param string $from Suspected charset of the input string + * @param string $to Target charset to convert to; defaults to RCUBE_CHARSET + * + * @return string Converted string + */ + public static function convert($str, $from, $to = null) + { + static $iconv_options; + + $to = empty($to) ? RCUBE_CHARSET : self::parse_charset($to); + $from = self::parse_charset($from); + + // It is a common case when UTF-16 charset is used with US-ASCII content (#1488654) + // In that case we can just skip the conversion (use UTF-8) + if ($from == 'UTF-16' && !preg_match('/[^\x00-\x7F]/', $str)) { + $from = 'UTF-8'; + } + + if ($from == $to || empty($str) || empty($from)) { + return $str; + } + + $out = false; + $error_handler = function() { throw new \Exception(); }; + + // Ignore invalid characters + $mbstring_sc = mb_substitute_character(); + mb_substitute_character('none'); + + // If mbstring reports an illegal character in input via E_WARNING. + // FIXME: Is this really true with substitute character 'none'? + // A warning is thrown in PHP<8 also on unsupported encoding, in PHP>=8 ValueError + // is thrown instead (therefore we catch Throwable below) + set_error_handler($error_handler, E_WARNING); + + try { + $out = mb_convert_encoding($str, $to, $from); + } + catch (Throwable $e) { + $out = false; + } + + restore_error_handler(); + mb_substitute_character($mbstring_sc); + + if ($out !== false) { + return $out; + } + + if ($iconv_options === null) { + if (function_exists('iconv')) { + // ignore characters not available in output charset + $iconv_options = '//IGNORE'; + if (iconv('', $iconv_options, '') === false) { + // iconv implementation does not support options + $iconv_options = ''; + } + } + else { + $iconv_options = false; + } + } + + // Fallback to iconv module, it is slower, but supports much more charsets than mbstring + if ($iconv_options !== false && $from != 'UTF7-IMAP' && $to != 'UTF7-IMAP' + && $from !== 'ISO-2022-JP' + ) { + // If iconv reports an illegal character in input it means that input string + // has been truncated. It's reported as E_NOTICE. + // PHP8 will also throw E_WARNING on unsupported encoding. + set_error_handler($error_handler, E_NOTICE | E_WARNING); + + try { + $out = iconv($from, $to . $iconv_options, $str); + } + catch (Throwable $e) { + $out = false; + } + + restore_error_handler(); + + if ($out !== false) { + return $out; + } + } + + // return the original string + return $str; + } + + /** + * Check if the specified input string matches one of the provided charsets. + * This includes UTF-32, UTF-16, RCUBE_CHARSET and default_charset. + * + * @param string $str Input string + * @param array $charsets Suspected charsets of the input string + * + * @return string|null First matching charset + */ + public static function check($str, $charsets = []) + { + $chunk = strlen($str) > 100 * 1024 ? substr($str, 0, 100 * 1024) : $str; + + // Add dehault charset, system charset and easily detectable charset to the list + if (substr($chunk, 0, 4) == "\0\0\xFE\xFF") $charsets[] = 'UTF-32BE'; + if (substr($chunk, 0, 4) == "\xFF\xFE\0\0") $charsets[] = 'UTF-32LE'; + if (substr($chunk, 0, 2) == "\xFE\xFF") $charsets[] = 'UTF-16BE'; + if (substr($chunk, 0, 2) == "\xFF\xFE") $charsets[] = 'UTF-16LE'; + + // heuristics + if (preg_match('/\x00\x00\x00[^\x00]/', $chunk)) $charsets[] = 'UTF-32BE'; + if (preg_match('/[^\x00]\x00\x00\x00/', $chunk)) $charsets[] = 'UTF-32LE'; + if (preg_match('/\x00[^\x00]\x00[^\x00]/', $chunk)) $charsets[] = 'UTF-16BE'; + if (preg_match('/[^\x00]\x00[^\x00]\x00/', $chunk)) $charsets[] = 'UTF-16LE'; + + $charsets[] = RCUBE_CHARSET; + $charsets[] = (string) rcube::get_instance()->config->get('default_charset'); + + $charsets = array_map(['rcube_charset', 'parse_charset'], $charsets); + $charsets = array_unique(array_filter($charsets)); + + foreach ($charsets as $charset) { + $ret = self::convert($chunk, $charset); + + if ($ret === rcube_charset::clean($ret)) { + return $charset; + } + } + } + + /** + * Converts string from standard UTF-7 (RFC 2152) to UTF-8. + * + * @param string $str Input string (UTF-7) + * + * @return string Converted string (UTF-8) + * @deprecated use self::convert() + */ + public static function utf7_to_utf8($str) + { + return self::convert($str, 'UTF-7', 'UTF-8'); + } + + /** + * Converts string from UTF-16 to UTF-8 (helper for utf-7 to utf-8 conversion) + * + * @param string $str Input string + * + * @return string The converted string + * @deprecated use self::convert() + */ + public static function utf16_to_utf8($str) + { + return self::convert($str, 'UTF-16BE', 'UTF-8'); + } + + /** + * Convert the data ($str) from RFC 2060's UTF-7 to UTF-8. + * If input data is invalid, return the original input string. + * RFC 2060 obviously intends the encoding to be unique (see + * point 5 in section 5.1.3), so we reject any non-canonical + * form, such as &ACY- (instead of &-) or &AMA-&AMA- (instead + * of &AMAAwA-). + * + * @param string $str Input string (UTF7-IMAP) + * + * @return string Output string (UTF-8) + * @deprecated use self::convert() + */ + public static function utf7imap_to_utf8($str) + { + return self::convert($str, 'UTF7-IMAP', 'UTF-8'); + } + + /** + * Convert the data ($str) from UTF-8 to RFC 2060's UTF-7. + * Unicode characters above U+FFFF are replaced by U+FFFE. + * If input data is invalid, return an empty string. + * + * @param string $str Input string (UTF-8) + * + * @return string Output string (UTF7-IMAP) + * @deprecated use self::convert() + */ + public static function utf8_to_utf7imap($str) + { + return self::convert($str, 'UTF-8', 'UTF7-IMAP'); + } + + /** + * A method to guess character set of a string. + * + * @param string $string String + * @param string $failover Default result for failover + * @param string $language User language + * + * @return string Charset name + * @deprecated + */ + public static function detect($string, $failover = null, $language = null) + { + if (substr($string, 0, 4) == "\0\0\xFE\xFF") return 'UTF-32BE'; // Big Endian + if (substr($string, 0, 4) == "\xFF\xFE\0\0") return 'UTF-32LE'; // Little Endian + if (substr($string, 0, 2) == "\xFE\xFF") return 'UTF-16BE'; // Big Endian + if (substr($string, 0, 2) == "\xFF\xFE") return 'UTF-16LE'; // Little Endian + if (substr($string, 0, 3) == "\xEF\xBB\xBF") return 'UTF-8'; + + // heuristics + if (strlen($string) >= 4) { + if ($string[0] == "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-32BE'; + if ($string[0] != "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] == "\0") return 'UTF-32LE'; + if ($string[0] == "\0" && $string[1] != "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-16BE'; + if ($string[0] != "\0" && $string[1] == "\0" && $string[2] != "\0" && $string[3] == "\0") return 'UTF-16LE'; + } + + if (empty($language)) { + $rcube = rcube::get_instance(); + $language = $rcube->get_user_language(); + } + + // Prioritize charsets according to the current language (#1485669) + $prio = null; + switch ($language) { + case 'ja_JP': + $prio = ['ISO-2022-JP', 'JIS', 'UTF-8', 'EUC-JP', 'eucJP-win', 'SJIS']; + break; + + case 'zh_CN': + case 'zh_TW': + $prio = ['UTF-8', 'BIG-5', 'EUC-TW', 'GB18030']; + break; + + case 'ko_KR': + $prio = ['UTF-8', 'EUC-KR', 'ISO-2022-KR']; + break; + + case 'ru_RU': + $prio = ['UTF-8', 'WINDOWS-1251', 'KOI8-R']; + break; + + case 'tr_TR': + $prio = ['UTF-8', 'ISO-8859-9', 'WINDOWS-1254']; + break; + } + + // mb_detect_encoding() is not reliable for some charsets (#1490135) + // use mb_check_encoding() to make charset priority lists really working + if (!empty($prio) && function_exists('mb_check_encoding')) { + foreach ($prio as $encoding) { + if (mb_check_encoding($string, $encoding)) { + return $encoding; + } + } + } + + if (function_exists('mb_detect_encoding')) { + $exclude = 'BASE64,UUENCODE,HTML-ENTITIES,Quoted-Printable,' + . '7bit,8bit,pass,wchar,byte2be,byte2le,byte4be,byte4le,' + . 'UCS-4,UCS-4BE,UCS-4LE,UCS-2,UCS-2BE,UCS-2LE'; + + if (empty($prio)) { + $prio = [ + 'UTF-8', + 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4', + 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9', + 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16', + 'WINDOWS-1252', 'WINDOWS-1251', 'WINDOWS-1254', + 'EUC-JP', 'EUC-TW', 'KOI8-R', 'BIG-5', 'ISO-2022-KR', 'ISO-2022-JP', 'GB18030', + ]; + } + + // We have to remove unwanted/uncommon encodings from the list. + // This is needed especially on PHP >= 8.1 + $all_encodings = array_diff(mb_list_encodings(), explode(',', $exclude)); + + $encodings = array_unique(array_merge($prio, $all_encodings)); + + if ($encoding = mb_detect_encoding($string, $encodings, true)) { + return $encoding; + } + } + + // No match, check for UTF-8 + // from http://w3.org/International/questions/qa-forms-utf-8.html + if (preg_match('/\A( + [\x09\x0A\x0D\x20-\x7E] + | [\xC2-\xDF][\x80-\xBF] + | \xE0[\xA0-\xBF][\x80-\xBF] + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} + | \xED[\x80-\x9F][\x80-\xBF] + | \xF0[\x90-\xBF][\x80-\xBF]{2} + | [\xF1-\xF3][\x80-\xBF]{3} + | \xF4[\x80-\x8F][\x80-\xBF]{2} + )*\z/xs', substr($string, 0, 2048)) + ) { + return 'UTF-8'; + } + + return $failover; + } + + /** + * Removes non-unicode characters from input. + * If the input is an array, both values and keys will be cleaned up. + * + * @param mixed $input String or array. + * + * @return mixed String or array + */ + public static function clean($input) + { + // handle input of type array + if (is_array($input)) { + foreach (array_keys($input) as $key) { + $k = is_string($key) ? self::clean($key) : $key; + $v = self::clean($input[$key]); + + if ($k !== $key) { + unset($input[$key]); + if (!array_key_exists($k, $input)) { + $input[$k] = $v; + } + } + else { + $input[$k] = $v; + } + } + return $input; + } + + if (!is_string($input) || $input == '') { + return $input; + } + + $msch = mb_substitute_character(); + mb_substitute_character('none'); + $res = mb_convert_encoding($input, 'UTF-8', 'UTF-8'); + mb_substitute_character($msch); + + return $res; + } +} diff --git a/admin/tool/messageinbound/roundcube/rcube_imap_generic.php b/admin/tool/messageinbound/roundcube/rcube_imap_generic.php new file mode 100644 index 00000000000..0ef84818f92 --- /dev/null +++ b/admin/tool/messageinbound/roundcube/rcube_imap_generic.php @@ -0,0 +1,4278 @@ + | + | Author: Ryo Chijiiwa | + +-----------------------------------------------------------------------+ +*/ + +/** + * PHP based wrapper class to connect to an IMAP server + * + * @package Framework + * @subpackage Storage + */ +class rcube_imap_generic +{ + public $error; + public $errornum; + public $result; + public $resultcode; + public $selected; + public $data = []; + public $flags = [ + 'SEEN' => '\\Seen', + 'DELETED' => '\\Deleted', + 'ANSWERED' => '\\Answered', + 'DRAFT' => '\\Draft', + 'FLAGGED' => '\\Flagged', + 'FORWARDED' => '$Forwarded', + 'MDNSENT' => '$MDNSent', + '*' => '\\*', + ]; + + protected $fp; + protected $host; + protected $user; + protected $cmd_tag; + protected $cmd_num = 0; + protected $resourceid; + protected $extensions_enabled; + protected $prefs = []; + protected $logged = false; + protected $capability = []; + protected $capability_read = false; + protected $debug = false; + protected $debug_handler = false; + + const ERROR_OK = 0; + const ERROR_NO = -1; + const ERROR_BAD = -2; + const ERROR_BYE = -3; + const ERROR_UNKNOWN = -4; + const ERROR_COMMAND = -5; + const ERROR_READONLY = -6; + + const COMMAND_NORESPONSE = 1; + const COMMAND_CAPABILITY = 2; + const COMMAND_LASTLINE = 4; + const COMMAND_ANONYMIZED = 8; + + const DEBUG_LINE_LENGTH = 4098; // 4KB + 2B for \r\n + + + /** + * Send simple (one line) command to the connection stream + * + * @param string $string Command string + * @param bool $endln True if CRLF need to be added at the end of command + * @param bool $anonymized Don't write the given data to log but a placeholder + * + * @return int Number of bytes sent, False on error + */ + protected function putLine($string, $endln = true, $anonymized = false) + { + if (!$this->fp) { + return false; + } + + if ($this->debug) { + // anonymize the sent command for logging + $cut = $endln ? 2 : 0; + if ($anonymized && preg_match('/^(A\d+ (?:[A-Z]+ )+)(.+)/', $string, $m)) { + $log = $m[1] . sprintf('****** [%d]', strlen($m[2]) - $cut); + } + else if ($anonymized) { + $log = sprintf('****** [%d]', strlen($string) - $cut); + } + else { + $log = rtrim($string); + } + + $this->debug('C: ' . $log); + } + + if ($endln) { + $string .= "\r\n"; + } + + $res = fwrite($this->fp, $string); + + if ($res === false) { + $this->closeSocket(); + } + + return $res; + } + + /** + * Send command to the connection stream with Command Continuation + * Requests (RFC3501 7.5) and LITERAL+ (RFC2088) and LITERAL- (RFC7888) support. + * + * @param string $string Command string + * @param bool $endln True if CRLF need to be added at the end of command + * @param bool $anonymized Don't write the given data to log but a placeholder + * + * @return int|bool Number of bytes sent, False on error + */ + protected function putLineC($string, $endln = true, $anonymized = false) + { + if (!$this->fp) { + return false; + } + + if ($endln) { + $string .= "\r\n"; + } + + $res = 0; + if ($parts = preg_split('/(\{[0-9]+\}\r\n)/m', $string, -1, PREG_SPLIT_DELIM_CAPTURE)) { + for ($i = 0, $cnt = count($parts); $i < $cnt; $i++) { + if ($i + 1 < $cnt && preg_match('/^\{([0-9]+)\}\r\n$/', $parts[$i+1], $matches)) { + // LITERAL+/LITERAL- support + $literal_plus = false; + if ( + !empty($this->prefs['literal+']) + || (!empty($this->prefs['literal-']) && $matches[1] <= 4096) + ) { + $parts[$i+1] = sprintf("{%d+}\r\n", $matches[1]); + $literal_plus = true; + } + + $bytes = $this->putLine($parts[$i].$parts[$i+1], false, $anonymized); + if ($bytes === false) { + return false; + } + + $res += $bytes; + + // don't wait if server supports LITERAL+ capability + if (!$literal_plus) { + $line = $this->readLine(1000); + // handle error in command + if (!isset($line[0]) || $line[0] != '+') { + return false; + } + } + + $i++; + } + else { + $bytes = $this->putLine($parts[$i], false, $anonymized); + if ($bytes === false) { + return false; + } + + $res += $bytes; + } + } + } + + return $res; + } + + /** + * Reads line from the connection stream + * + * @param int $size Buffer size + * + * @return string Line of text response + */ + protected function readLine($size = 1024) + { + $line = ''; + + if (!$size) { + $size = 1024; + } + + do { + if ($this->eof()) { + return $line; + } + + $buffer = fgets($this->fp, $size); + + if ($buffer === false) { + $this->closeSocket(); + break; + } + + if ($this->debug) { + $this->debug('S: '. rtrim($buffer)); + } + + $line .= $buffer; + } + while (substr($buffer, -1) != "\n"); + + return $line; + } + + /** + * Reads a line of data from the connection stream including all + * string continuation literals. + * + * @param int $size Buffer size + * + * @return string Line of text response + */ + protected function readFullLine($size = 1024) + { + $line = $this->readLine($size); + + // include all string literals untile the real end of "line" + while (preg_match('/\{([0-9]+)\}\r\n$/', $line, $m)) { + $bytes = $m[1]; + $out = ''; + + while (strlen($out) < $bytes) { + $out = $this->readBytes($bytes); + if ($out === '') { + break; + } + + $line .= $out; + } + + $line .= $this->readLine($size); + } + + return $line; + } + + /** + * Reads more data from the connection stream when provided + * data contain string literal + * + * @param string $line Response text + * @param bool $escape Enables escaping + * + * @return string Line of text response + */ + protected function multLine($line, $escape = false) + { + $line = rtrim($line); + if (preg_match('/\{([0-9]+)\}$/', $line, $m)) { + $out = ''; + $str = substr($line, 0, -strlen($m[0])); + $bytes = $m[1]; + + while (strlen($out) < $bytes) { + $line = $this->readBytes($bytes); + if ($line === '') { + break; + } + + $out .= $line; + } + + $line = $str . ($escape ? $this->escape($out) : $out); + } + + return $line; + } + + /** + * Reads specified number of bytes from the connection stream + * + * @param int $bytes Number of bytes to get + * + * @return string Response text + */ + protected function readBytes($bytes) + { + $data = ''; + $len = 0; + + while ($len < $bytes && !$this->eof()) { + $d = fread($this->fp, $bytes-$len); + if ($this->debug) { + $this->debug('S: '. $d); + } + $data .= $d; + $data_len = strlen($data); + if ($len == $data_len) { + break; // nothing was read -> exit to avoid apache lockups + } + $len = $data_len; + } + + return $data; + } + + /** + * Reads complete response to the IMAP command + * + * @param array $untagged Will be filled with untagged response lines + * + * @return string Response text + */ + protected function readReply(&$untagged = null) + { + while (true) { + $line = trim($this->readLine(1024)); + // store untagged response lines + if (isset($line[0]) && $line[0] == '*') { + $untagged[] = $line; + } + else { + break; + } + } + + if ($untagged) { + $untagged = implode("\n", $untagged); + } + + return $line; + } + + /** + * Response parser. + * + * @param string $string Response text + * @param string $err_prefix Error message prefix + * + * @return int Response status + */ + protected function parseResult($string, $err_prefix = '') + { + if (preg_match('/^[a-z0-9*]+ (OK|NO|BAD|BYE)(.*)$/i', trim($string), $matches)) { + $res = strtoupper($matches[1]); + $str = trim($matches[2]); + + if ($res == 'OK') { + $this->errornum = self::ERROR_OK; + } + else if ($res == 'NO') { + $this->errornum = self::ERROR_NO; + } + else if ($res == 'BAD') { + $this->errornum = self::ERROR_BAD; + } + else if ($res == 'BYE') { + $this->closeSocket(); + $this->errornum = self::ERROR_BYE; + } + + if ($str) { + $str = trim($str); + // get response string and code (RFC5530) + if (preg_match("/^\[([a-z-]+)\]/i", $str, $m)) { + $this->resultcode = strtoupper($m[1]); + $str = trim(substr($str, strlen($m[1]) + 2)); + } + else { + $this->resultcode = null; + // parse response for [APPENDUID 1204196876 3456] + if (preg_match("/^\[APPENDUID [0-9]+ ([0-9]+)\]/i", $str, $m)) { + $this->data['APPENDUID'] = $m[1]; + } + // parse response for [COPYUID 1204196876 3456:3457 123:124] + else if (preg_match("/^\[COPYUID [0-9]+ ([0-9,:]+) ([0-9,:]+)\]/i", $str, $m)) { + $this->data['COPYUID'] = [$m[1], $m[2]]; + } + } + + $this->result = $str; + + if ($this->errornum != self::ERROR_OK) { + $this->error = $err_prefix ? $err_prefix.$str : $str; + } + } + + return $this->errornum; + } + + return self::ERROR_UNKNOWN; + } + + /** + * Checks connection stream state. + * + * @return bool True if connection is closed + */ + protected function eof() + { + if (!$this->fp) { + return true; + } + + // If a connection opened by fsockopen() wasn't closed + // by the server, feof() will hang. + $start = microtime(true); + + if (feof($this->fp) || + ($this->prefs['timeout'] && (microtime(true) - $start > $this->prefs['timeout'])) + ) { + $this->closeSocket(); + return true; + } + + return false; + } + + /** + * Closes connection stream. + */ + protected function closeSocket() + { + if ($this->fp) { + fclose($this->fp); + $this->fp = null; + } + } + + /** + * Error code/message setter. + */ + protected function setError($code, $msg = '') + { + $this->errornum = $code; + $this->error = $msg; + + return $code; + } + + /** + * Checks response status. + * Checks if command response line starts with specified prefix (or * BYE/BAD) + * + * @param string $string Response text + * @param string $match Prefix to match with (case-sensitive) + * @param bool $error Enables BYE/BAD checking + * @param bool $nonempty Enables empty response checking + * + * @return bool True any check is true or connection is closed. + */ + protected function startsWith($string, $match, $error = false, $nonempty = false) + { + if (!$this->fp) { + return true; + } + + if (strncmp($string, $match, strlen($match)) == 0) { + return true; + } + + if ($error && preg_match('/^\* (BYE|BAD) /i', $string, $m)) { + if (strtoupper($m[1]) == 'BYE') { + $this->closeSocket(); + } + return true; + } + + if ($nonempty && !strlen($string)) { + return true; + } + + return false; + } + + /** + * Capabilities checker + */ + protected function hasCapability($name) + { + if (empty($this->capability) || empty($name)) { + return false; + } + + if (in_array($name, $this->capability)) { + return true; + } + else if (strpos($name, '=')) { + return false; + } + + $result = []; + foreach ($this->capability as $cap) { + $entry = explode('=', $cap); + if ($entry[0] == $name) { + $result[] = $entry[1]; + } + } + + return $result ?: false; + } + + /** + * Capabilities checker + * + * @param string $name Capability name + * + * @return mixed Capability values array for key=value pairs, true/false for others + */ + public function getCapability($name) + { + $result = $this->hasCapability($name); + + if (!empty($result)) { + return $result; + } + else if ($this->capability_read) { + return false; + } + + // get capabilities (only once) because initial + // optional CAPABILITY response may differ + $result = $this->execute('CAPABILITY'); + + if ($result[0] == self::ERROR_OK) { + $this->parseCapability($result[1]); + } + + $this->capability_read = true; + + return $this->hasCapability($name); + } + + /** + * Clears detected server capabilities + */ + public function clearCapability() + { + $this->capability = []; + $this->capability_read = false; + } + + /** + * DIGEST-MD5/CRAM-MD5/PLAIN Authentication + * + * @param string $user Username + * @param string $pass Password + * @param string $type Authentication type (PLAIN/CRAM-MD5/DIGEST-MD5) + * + * @return resource|int Connection resource on success, error code on error + */ + protected function authenticate($user, $pass, $type = 'PLAIN') + { + if ($type == 'CRAM-MD5' || $type == 'DIGEST-MD5') { + if ($type == 'DIGEST-MD5' && !class_exists('Auth_SASL')) { + return $this->setError(self::ERROR_BYE, + "The Auth_SASL package is required for DIGEST-MD5 authentication"); + } + + $this->putLine($this->nextTag() . " AUTHENTICATE $type"); + $line = trim($this->readReply()); + + if ($line[0] == '+') { + $challenge = substr($line, 2); + } + else { + return $this->parseResult($line); + } + + if ($type == 'CRAM-MD5') { + // RFC2195: CRAM-MD5 + $ipad = ''; + $opad = ''; + $xor = function($str1, $str2) { + $result = ''; + $size = strlen($str1); + for ($i=0; $i<$size; $i++) { + $result .= chr(ord($str1[$i]) ^ ord($str2[$i])); + } + return $result; + }; + + // initialize ipad, opad + for ($i=0; $i<64; $i++) { + $ipad .= chr(0x36); + $opad .= chr(0x5C); + } + + // pad $pass so it's 64 bytes + $pass = str_pad($pass, 64, chr(0)); + + // generate hash + $hash = md5($xor($pass, $opad) . pack("H*", + md5($xor($pass, $ipad) . base64_decode($challenge)))); + $reply = base64_encode($user . ' ' . $hash); + + // send result + $this->putLine($reply, true, true); + } + else { + // RFC2831: DIGEST-MD5 + // proxy authorization + if (!empty($this->prefs['auth_cid'])) { + $authc = $this->prefs['auth_cid']; + $pass = $this->prefs['auth_pw']; + } + else { + $authc = $user; + $user = ''; + } + + $auth_sasl = new Auth_SASL; + $auth_sasl = $auth_sasl->factory('digestmd5'); + $reply = base64_encode($auth_sasl->getResponse($authc, $pass, + base64_decode($challenge), $this->host, 'imap', $user)); + + // send result + $this->putLine($reply, true, true); + $line = trim($this->readReply()); + + if ($line[0] != '+') { + return $this->parseResult($line); + } + + // check response + $challenge = substr($line, 2); + $challenge = base64_decode($challenge); + if (strpos($challenge, 'rspauth=') === false) { + return $this->setError(self::ERROR_BAD, + "Unexpected response from server to DIGEST-MD5 response"); + } + + $this->putLine(''); + } + + $line = $this->readReply(); + $result = $this->parseResult($line); + } + else if ($type == 'GSSAPI') { + if (!extension_loaded('krb5')) { + return $this->setError(self::ERROR_BYE, + "The krb5 extension is required for GSSAPI authentication"); + } + + if (empty($this->prefs['gssapi_cn'])) { + return $this->setError(self::ERROR_BYE, + "The gssapi_cn parameter is required for GSSAPI authentication"); + } + + if (empty($this->prefs['gssapi_context'])) { + return $this->setError(self::ERROR_BYE, + "The gssapi_context parameter is required for GSSAPI authentication"); + } + + putenv('KRB5CCNAME=' . $this->prefs['gssapi_cn']); + + try { + $ccache = new KRB5CCache(); + $ccache->open($this->prefs['gssapi_cn']); + $gssapicontext = new GSSAPIContext(); + $gssapicontext->acquireCredentials($ccache); + + $token = ''; + $success = $gssapicontext->initSecContext($this->prefs['gssapi_context'], null, null, null, $token); + $token = base64_encode($token); + } + catch (Exception $e) { + trigger_error($e->getMessage(), E_USER_WARNING); + return $this->setError(self::ERROR_BYE, "GSSAPI authentication failed"); + } + + $this->putLine($this->nextTag() . " AUTHENTICATE GSSAPI " . $token); + $line = trim($this->readReply()); + + if ($line[0] != '+') { + return $this->parseResult($line); + } + + try { + $itoken = base64_decode(substr($line, 2)); + + if (!$gssapicontext->unwrap($itoken, $itoken)) { + throw new Exception("GSSAPI SASL input token unwrap failed"); + } + + if (strlen($itoken) < 4) { + throw new Exception("GSSAPI SASL input token invalid"); + } + + // Integrity/encryption layers are not supported. The first bit + // indicates that the server supports "no security layers". + // 0x00 should not occur, but support broken implementations. + $server_layers = ord($itoken[0]); + if ($server_layers && ($server_layers & 0x1) != 0x1) { + throw new Exception("Server requires GSSAPI SASL integrity/encryption"); + } + + // Construct output token. 0x01 in the first octet = SASL layer "none", + // zero in the following three octets = no data follows. + // See https://github.com/cyrusimap/cyrus-sasl/blob/e41cfb986c1b1935770de554872247453fdbb079/plugins/gssapi.c#L1284 + if (!$gssapicontext->wrap(pack("CCCC", 0x1, 0, 0, 0), $otoken, true)) { + throw new Exception("GSSAPI SASL output token wrap failed"); + } + } + catch (Exception $e) { + trigger_error($e->getMessage(), E_USER_WARNING); + return $this->setError(self::ERROR_BYE, "GSSAPI authentication failed"); + } + + $this->putLine(base64_encode($otoken)); + + $line = $this->readReply(); + $result = $this->parseResult($line); + } + else if ($type == 'PLAIN') { + // proxy authorization + if (!empty($this->prefs['auth_cid'])) { + $authc = $this->prefs['auth_cid']; + $pass = $this->prefs['auth_pw']; + } + else { + $authc = $user; + $user = ''; + } + + $reply = base64_encode($user . chr(0) . $authc . chr(0) . $pass); + + // RFC 4959 (SASL-IR): save one round trip + if ($this->getCapability('SASL-IR')) { + list($result, $line) = $this->execute("AUTHENTICATE PLAIN", [$reply], + self::COMMAND_LASTLINE | self::COMMAND_CAPABILITY | self::COMMAND_ANONYMIZED); + } + else { + $this->putLine($this->nextTag() . " AUTHENTICATE PLAIN"); + $line = trim($this->readReply()); + + if ($line[0] != '+') { + return $this->parseResult($line); + } + + // send result, get reply and process it + $this->putLine($reply, true, true); + $line = $this->readReply(); + $result = $this->parseResult($line); + } + } + else if ($type == 'LOGIN') { + $this->putLine($this->nextTag() . " AUTHENTICATE LOGIN"); + + $line = trim($this->readReply()); + if ($line[0] != '+') { + return $this->parseResult($line); + } + + $this->putLine(base64_encode($user), true, true); + + $line = trim($this->readReply()); + if ($line[0] != '+') { + return $this->parseResult($line); + } + + // send result, get reply and process it + $this->putLine(base64_encode($pass), true, true); + + $line = $this->readReply(); + $result = $this->parseResult($line); + } + else if ($type == 'XOAUTH2') { + $auth = base64_encode("user=$user\1auth=$pass\1\1"); + $this->putLine($this->nextTag() . " AUTHENTICATE XOAUTH2 $auth", true, true); + + $line = trim($this->readReply()); + + if ($line[0] == '+') { + // send empty line + $this->putLine('', true, true); + $line = $this->readReply(); + } + + $result = $this->parseResult($line); + } + else { + $line = 'not supported'; + $result = self::ERROR_UNKNOWN; + } + + if ($result === self::ERROR_OK) { + // optional CAPABILITY response + if ($line && preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { + $this->parseCapability($matches[1], true); + } + + return $this->fp; + } + + return $this->setError($result, "AUTHENTICATE $type: $line"); + } + + /** + * LOGIN Authentication + * + * @param string $user Username + * @param string $password Password + * + * @return resource|int Connection resource on success, error code on error + */ + protected function login($user, $password) + { + // Prevent from sending credentials in plain text when connection is not secure + if ($this->getCapability('LOGINDISABLED')) { + return $this->setError(self::ERROR_BAD, "Login disabled by IMAP server"); + } + + list($code, $response) = $this->execute('LOGIN', [$this->escape($user, true), $this->escape($password, true)], + self::COMMAND_CAPABILITY | self::COMMAND_ANONYMIZED); + + // re-set capabilities list if untagged CAPABILITY response provided + if (preg_match('/\* CAPABILITY (.+)/i', $response, $matches)) { + $this->parseCapability($matches[1], true); + } + + if ($code == self::ERROR_OK) { + return $this->fp; + } + + return $code; + } + + /** + * Detects hierarchy delimiter + * + * @return string The delimiter + */ + public function getHierarchyDelimiter() + { + if (!empty($this->prefs['delimiter'])) { + return $this->prefs['delimiter']; + } + + // try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8) + list($code, $response) = $this->execute('LIST', [$this->escape(''), $this->escape('')]); + + if ($code == self::ERROR_OK) { + $args = $this->tokenizeResponse($response, 4); + $delimiter = $args[3]; + + if (strlen($delimiter) > 0) { + return ($this->prefs['delimiter'] = $delimiter); + } + } + } + + /** + * NAMESPACE handler (RFC 2342) + * + * @return array Namespace data hash (personal, other, shared) + */ + public function getNamespace() + { + if (array_key_exists('namespace', $this->prefs)) { + return $this->prefs['namespace']; + } + + if (!$this->getCapability('NAMESPACE')) { + return self::ERROR_BAD; + } + + list($code, $response) = $this->execute('NAMESPACE'); + + if ($code == self::ERROR_OK && preg_match('/^\* NAMESPACE /', $response)) { + $response = substr($response, 11); + $data = $this->tokenizeResponse($response); + } + + if (!isset($data) || !is_array($data)) { + return $code; + } + + $this->prefs['namespace'] = [ + 'personal' => $data[0], + 'other' => $data[1], + 'shared' => $data[2], + ]; + + return $this->prefs['namespace']; + } + + /** + * Connects to IMAP server and authenticates. + * + * @param string $host Server hostname or IP + * @param string $user User name + * @param string $password Password + * @param array $options Connection and class options + * + * @return bool True on success, False on failure + */ + public function connect($host, $user, $password, $options = []) + { + // configure + $this->set_prefs($options); + + $this->host = $host; + $this->user = $user; + $this->logged = false; + $this->selected = null; + + // check input + if (empty($host)) { + $this->setError(self::ERROR_BAD, "Empty host"); + return false; + } + + if (empty($user)) { + $this->setError(self::ERROR_NO, "Empty user"); + return false; + } + + if (empty($password) && empty($options['gssapi_cn'])) { + $this->setError(self::ERROR_NO, "Empty password"); + return false; + } + + // Connect + if (!$this->_connect($host)) { + return false; + } + + // Send pre authentication ID info (#7860) + if (!empty($this->prefs['preauth_ident']) && $this->getCapability('ID')) { + $this->data['ID'] = $this->id($this->prefs['preauth_ident']); + } + + $auth_method = $this->prefs['auth_type']; + $auth_methods = []; + $result = null; + + // check for supported auth methods + if (!$auth_method || $auth_method == 'CHECK') { + if ($auth_caps = $this->getCapability('AUTH')) { + $auth_methods = $auth_caps; + } + + // Use best (for security) supported authentication method + $all_methods = ['DIGEST-MD5', 'CRAM-MD5', 'CRAM_MD5', 'PLAIN', 'LOGIN']; + + if (!empty($this->prefs['gssapi_cn'])) { + array_unshift($all_methods, 'GSSAPI'); + } + + foreach ($all_methods as $auth_method) { + if (in_array($auth_method, $auth_methods)) { + break; + } + } + + // Prefer LOGIN over AUTHENTICATE LOGIN for performance reasons + if ($auth_method == 'LOGIN' && !$this->getCapability('LOGINDISABLED')) { + $auth_method = 'IMAP'; + } + } + + // pre-login capabilities can be not complete + $this->capability_read = false; + + // Authenticate + switch ($auth_method) { + case 'CRAM_MD5': + $auth_method = 'CRAM-MD5'; + case 'CRAM-MD5': + case 'DIGEST-MD5': + case 'GSSAPI': + case 'PLAIN': + case 'LOGIN': + case 'XOAUTH2': + $result = $this->authenticate($user, $password, $auth_method); + break; + + case 'IMAP': + $result = $this->login($user, $password); + break; + + default: + $this->setError(self::ERROR_BAD, "Configuration error. Unknown auth method: $auth_method"); + } + + // Connected and authenticated + if (is_resource($result)) { + if (!empty($this->prefs['force_caps'])) { + $this->clearCapability(); + } + + $this->logged = true; + + // Send ID info after authentication to ensure reliable result (#7517) + if (!empty($this->prefs['ident']) && $this->getCapability('ID')) { + $this->data['ID'] = $this->id($this->prefs['ident']); + } + + return true; + } + + $this->closeConnection(); + + return false; + } + + /** + * Connects to IMAP server. + * + * @param string $host Server hostname or IP + * + * @return bool True on success, False on failure + */ + protected function _connect($host) + { + // initialize connection + $this->error = ''; + $this->errornum = self::ERROR_OK; + + $port = empty($this->prefs['port']) ? 143 : $this->prefs['port']; + $ssl_mode = $this->prefs['ssl_mode'] ?? null; + + // check for SSL + if (!empty($ssl_mode) && $ssl_mode != 'tls') { + $host = $ssl_mode . '://' . $host; + } + + if (empty($this->prefs['timeout']) || $this->prefs['timeout'] < 0) { + $this->prefs['timeout'] = max(0, intval(ini_get('default_socket_timeout'))); + } + + if ($this->debug) { + // set connection identifier for debug output + $this->resourceid = strtoupper(substr(md5(microtime() . $host . $this->user), 0, 4)); + + $_host = ($ssl_mode == 'tls' ? 'tls://' : '') . $host . ':' . $port; + $this->debug("Connecting to $_host..."); + } + + if (!empty($this->prefs['socket_options'])) { + $options = array_intersect_key($this->prefs['socket_options'], ['ssl' => 1]); + $context = stream_context_create($options); + $this->fp = stream_socket_client($host . ':' . $port, $errno, $errstr, + $this->prefs['timeout'], STREAM_CLIENT_CONNECT, $context); + } + else { + $this->fp = @fsockopen($host, $port, $errno, $errstr, $this->prefs['timeout']); + } + + if (!$this->fp) { + $this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", + $host, $port, $errstr ?: "Unknown reason")); + + return false; + } + + if ($this->prefs['timeout'] > 0) { + stream_set_timeout($this->fp, $this->prefs['timeout']); + } + + $line = trim(fgets($this->fp, 8192)); + + if ($this->debug && $line) { + $this->debug('S: '. $line); + } + + // Connected to wrong port or connection error? + if (!preg_match('/^\* (OK|PREAUTH)/i', $line)) { + if ($line) { + $error = sprintf("Wrong startup greeting (%s:%d): %s", $host, $port, $line); + } + else { + $error = sprintf("Empty startup greeting (%s:%d)", $host, $port); + } + + $this->setError(self::ERROR_BAD, $error); + $this->closeConnection(); + return false; + } + + $this->data['GREETING'] = trim(preg_replace('/\[[^\]]+\]\s*/', '', $line)); + + // RFC3501 [7.1] optional CAPABILITY response + if (preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches)) { + $this->parseCapability($matches[1], true); + } + + // TLS connection + if ($ssl_mode == 'tls' && $this->getCapability('STARTTLS')) { + $res = $this->execute('STARTTLS'); + + if (empty($res) || $res[0] != self::ERROR_OK) { + $this->closeConnection(); + return false; + } + + if (isset($this->prefs['socket_options']['ssl']['crypto_method'])) { + $crypto_method = $this->prefs['socket_options']['ssl']['crypto_method']; + } + else { + // There is no flag to enable all TLS methods. Net_SMTP + // handles enabling TLS similarly. + $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT + | @STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT + | @STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + } + + if (!stream_socket_enable_crypto($this->fp, true, $crypto_method)) { + $this->setError(self::ERROR_BAD, "Unable to negotiate TLS"); + $this->closeConnection(); + return false; + } + + // Now we're secure, capabilities need to be reread + $this->clearCapability(); + } + + return true; + } + + /** + * Initializes environment + */ + protected function set_prefs($prefs) + { + // set preferences + if (is_array($prefs)) { + $this->prefs = $prefs; + } + + // set auth method + if (!empty($this->prefs['auth_type'])) { + $this->prefs['auth_type'] = strtoupper($this->prefs['auth_type']); + } + else { + $this->prefs['auth_type'] = 'CHECK'; + } + + // disabled capabilities + if (!empty($this->prefs['disabled_caps'])) { + $this->prefs['disabled_caps'] = array_map('strtoupper', (array)$this->prefs['disabled_caps']); + } + + // additional message flags + if (!empty($this->prefs['message_flags'])) { + $this->flags = array_merge($this->flags, $this->prefs['message_flags']); + unset($this->prefs['message_flags']); + } + } + + /** + * Checks connection status + * + * @return bool True if connection is active and user is logged in, False otherwise. + */ + public function connected() + { + return $this->fp && $this->logged; + } + + /** + * Closes connection with logout. + */ + public function closeConnection() + { + if ($this->logged && $this->putLine($this->nextTag() . ' LOGOUT')) { + $this->readReply(); + } + + $this->closeSocket(); + $this->clearCapability(); + } + + /** + * Executes SELECT command (if mailbox is already not in selected state) + * + * @param string $mailbox Mailbox name + * @param array $qresync_data QRESYNC data (RFC5162) + * + * @return bool True on success, false on error + */ + public function select($mailbox, $qresync_data = null) + { + if (!strlen($mailbox)) { + return false; + } + + if ($this->selected === $mailbox) { + return true; + } + + $params = [$this->escape($mailbox)]; + + // QRESYNC data items + // 0. the last known UIDVALIDITY, + // 1. the last known modification sequence, + // 2. the optional set of known UIDs, and + // 3. an optional parenthesized list of known sequence ranges and their + // corresponding UIDs. + if (!empty($qresync_data)) { + if (!empty($qresync_data[2])) { + $qresync_data[2] = self::compressMessageSet($qresync_data[2]); + } + + $params[] = ['QRESYNC', $qresync_data]; + } + + list($code, $response) = $this->execute('SELECT', $params); + + if ($code == self::ERROR_OK) { + $this->clear_mailbox_cache(); + + $response = explode("\r\n", $response); + foreach ($response as $line) { + if (preg_match('/^\* OK \[/i', $line)) { + $pos = strcspn($line, ' ]', 6); + $token = strtoupper(substr($line, 6, $pos)); + $pos += 7; + + switch ($token) { + case 'UIDNEXT': + case 'UIDVALIDITY': + case 'UNSEEN': + if ($len = strspn($line, '0123456789', $pos)) { + $this->data[$token] = (int) substr($line, $pos, $len); + } + break; + + case 'HIGHESTMODSEQ': + if ($len = strspn($line, '0123456789', $pos)) { + $this->data[$token] = (string) substr($line, $pos, $len); + } + break; + + case 'NOMODSEQ': + $this->data[$token] = true; + break; + + case 'PERMANENTFLAGS': + $start = strpos($line, '(', $pos); + $end = strrpos($line, ')'); + if ($start && $end) { + $flags = substr($line, $start + 1, $end - $start - 1); + $this->data[$token] = explode(' ', $flags); + } + break; + } + } + else if (preg_match('/^\* ([0-9]+) (EXISTS|RECENT|FETCH)/i', $line, $match)) { + $token = strtoupper($match[2]); + switch ($token) { + case 'EXISTS': + case 'RECENT': + $this->data[$token] = (int) $match[1]; + break; + + case 'FETCH': + // QRESYNC FETCH response (RFC5162) + $line = substr($line, strlen($match[0])); + $fetch_data = $this->tokenizeResponse($line, 1); + $data = ['id' => $match[1]]; + + for ($i=0, $size=count($fetch_data); $i<$size; $i+=2) { + $data[strtolower($fetch_data[$i])] = $fetch_data[$i+1]; + } + + $this->data['QRESYNC'][$data['uid']] = $data; + break; + } + } + // QRESYNC VANISHED response (RFC5162) + else if (preg_match('/^\* VANISHED [()EARLIER]*/i', $line, $match)) { + $line = substr($line, strlen($match[0])); + $v_data = $this->tokenizeResponse($line, 1); + + $this->data['VANISHED'] = $v_data; + } + } + + $this->data['READ-WRITE'] = $this->resultcode != 'READ-ONLY'; + $this->selected = $mailbox; + + return true; + } + + return false; + } + + /** + * Executes STATUS command + * + * @param string $mailbox Mailbox name + * @param array $items Additional requested item names. By default + * MESSAGES and UNSEEN are requested. Other defined + * in RFC3501: UIDNEXT, UIDVALIDITY, RECENT + * + * @return array Status item-value hash + * @since 0.5-beta + */ + public function status($mailbox, $items = []) + { + if (!strlen($mailbox)) { + return false; + } + + if (!in_array('MESSAGES', $items)) { + $items[] = 'MESSAGES'; + } + if (!in_array('UNSEEN', $items)) { + $items[] = 'UNSEEN'; + } + + list($code, $response) = $this->execute('STATUS', + [$this->escape($mailbox), '(' . implode(' ', $items) . ')'], 0, '/^\* STATUS /i'); + + if ($code == self::ERROR_OK && $response) { + $result = []; + $response = substr($response, 9); // remove prefix "* STATUS " + + list($mbox, $items) = $this->tokenizeResponse($response, 2); + + // Fix for #1487859. Some buggy server returns not quoted + // folder name with spaces. Let's try to handle this situation + if (!is_array($items) && ($pos = strpos($response, '(')) !== false) { + $response = substr($response, $pos); + $items = $this->tokenizeResponse($response, 1); + } + + if (!is_array($items)) { + return $result; + } + + for ($i=0, $len=count($items); $i<$len; $i += 2) { + $result[$items[$i]] = $items[$i+1]; + } + + $this->data['STATUS:'.$mailbox] = $result; + + return $result; + } + + return false; + } + + /** + * Executes EXPUNGE command + * + * @param string $mailbox Mailbox name + * @param string|array $messages Message UIDs to expunge + * + * @return bool True on success, False on error + */ + public function expunge($mailbox, $messages = null) + { + if (!$this->select($mailbox)) { + return false; + } + + if (empty($this->data['READ-WRITE'])) { + $this->setError(self::ERROR_READONLY, "Mailbox is read-only"); + return false; + } + + // Clear internal status cache + $this->clear_status_cache($mailbox); + + if (!empty($messages) && $messages != '*' && $this->hasCapability('UIDPLUS')) { + $messages = self::compressMessageSet($messages); + $result = $this->execute('UID EXPUNGE', [$messages], self::COMMAND_NORESPONSE); + } + else { + $result = $this->execute('EXPUNGE', null, self::COMMAND_NORESPONSE); + } + + if ($result == self::ERROR_OK) { + $this->selected = null; // state has changed, need to reselect + return true; + } + + return false; + } + + /** + * Executes CLOSE command + * + * @return bool True on success, False on error + * @since 0.5 + */ + public function close() + { + $result = $this->execute('CLOSE', null, self::COMMAND_NORESPONSE); + + if ($result == self::ERROR_OK) { + $this->selected = null; + return true; + } + + return false; + } + + /** + * Folder subscription (SUBSCRIBE) + * + * @param string $mailbox Mailbox name + * + * @return bool True on success, False on error + */ + public function subscribe($mailbox) + { + $result = $this->execute('SUBSCRIBE', [$this->escape($mailbox)], self::COMMAND_NORESPONSE); + + return $result == self::ERROR_OK; + } + + /** + * Folder unsubscription (UNSUBSCRIBE) + * + * @param string $mailbox Mailbox name + * + * @return bool True on success, False on error + */ + public function unsubscribe($mailbox) + { + $result = $this->execute('UNSUBSCRIBE', [$this->escape($mailbox)], self::COMMAND_NORESPONSE); + + return $result == self::ERROR_OK; + } + + /** + * Folder creation (CREATE) + * + * @param string $mailbox Mailbox name + * @param array $types Optional folder types (RFC 6154) + * + * @return bool True on success, False on error + */ + public function createFolder($mailbox, $types = null) + { + $args = [$this->escape($mailbox)]; + + // RFC 6154: CREATE-SPECIAL-USE + if (!empty($types) && $this->getCapability('CREATE-SPECIAL-USE')) { + $args[] = '(USE (' . implode(' ', $types) . '))'; + } + + $result = $this->execute('CREATE', $args, self::COMMAND_NORESPONSE); + + return $result == self::ERROR_OK; + } + + /** + * Folder renaming (RENAME) + * + * @param string $from Mailbox name + * @param string $to Mailbox name + * + * @return bool True on success, False on error + */ + public function renameFolder($from, $to) + { + $result = $this->execute('RENAME', [$this->escape($from), $this->escape($to)], self::COMMAND_NORESPONSE); + + return $result == self::ERROR_OK; + } + + /** + * Executes DELETE command + * + * @param string $mailbox Mailbox name + * + * @return bool True on success, False on error + */ + public function deleteFolder($mailbox) + { + // Unselect the folder to prevent "BYE Fatal error: Mailbox has been (re)moved" on Cyrus IMAP + if ($this->selected === $mailbox && $this->hasCapability('UNSELECT')) { + $this->execute('UNSELECT', [], self::COMMAND_NORESPONSE); + } + + $result = $this->execute('DELETE', [$this->escape($mailbox)], self::COMMAND_NORESPONSE); + + return $result == self::ERROR_OK; + } + + /** + * Removes all messages in a folder + * + * @param string $mailbox Mailbox name + * + * @return bool True on success, False on error + */ + public function clearFolder($mailbox) + { + if ($this->countMessages($mailbox) > 0) { + $res = $this->flag($mailbox, '1:*', 'DELETED'); + } + else { + return true; + } + + if (!empty($res)) { + if ($this->selected === $mailbox) { + $res = $this->close(); + } + else { + $res = $this->expunge($mailbox); + } + + return $res; + } + + return false; + } + + /** + * Returns list of mailboxes + * + * @param string $ref Reference name + * @param string $mailbox Mailbox name + * @param array $return_opts (see self::_listMailboxes) + * @param array $select_opts (see self::_listMailboxes) + * + * @return array|bool List of mailboxes or hash of options if STATUS/MYRIGHTS response + * is requested, False on error. + */ + public function listMailboxes($ref, $mailbox, $return_opts = [], $select_opts = []) + { + return $this->_listMailboxes($ref, $mailbox, false, $return_opts, $select_opts); + } + + /** + * Returns list of subscribed mailboxes + * + * @param string $ref Reference name + * @param string $mailbox Mailbox name + * @param array $return_opts (see self::_listMailboxes) + * + * @return array|bool List of mailboxes or hash of options if STATUS/MYRIGHTS response + * is requested, False on error. + */ + public function listSubscribed($ref, $mailbox, $return_opts = []) + { + return $this->_listMailboxes($ref, $mailbox, true, $return_opts, null); + } + + /** + * IMAP LIST/LSUB command + * + * @param string $ref Reference name + * @param string $mailbox Mailbox name + * @param bool $subscribed Enables returning subscribed mailboxes only + * @param array $return_opts List of RETURN options (RFC5819: LIST-STATUS, RFC5258: LIST-EXTENDED) + * Possible: MESSAGES, RECENT, UIDNEXT, UIDVALIDITY, UNSEEN, + * MYRIGHTS, SUBSCRIBED, CHILDREN + * @param array $select_opts List of selection options (RFC5258: LIST-EXTENDED) + * Possible: SUBSCRIBED, RECURSIVEMATCH, REMOTE, + * SPECIAL-USE (RFC6154) + * + * @return array|bool List of mailboxes or hash of options if STATUS/MYRIGHTS response + * is requested, False on error. + */ + protected function _listMailboxes($ref, $mailbox, $subscribed = false, $return_opts = [], $select_opts = []) + { + if (!strlen($mailbox)) { + $mailbox = '*'; + } + + $lstatus = false; + $args = []; + $rets = []; + + if (!empty($select_opts) && $this->getCapability('LIST-EXTENDED')) { + $select_opts = (array) $select_opts; + + $args[] = '(' . implode(' ', $select_opts) . ')'; + } + + $args[] = $this->escape($ref); + $args[] = $this->escape($mailbox); + + if (!empty($return_opts) && $this->getCapability('LIST-EXTENDED')) { + $ext_opts = ['SUBSCRIBED', 'CHILDREN']; + $rets = array_intersect($return_opts, $ext_opts); + $return_opts = array_diff($return_opts, $rets); + } + + if (!empty($return_opts) && $this->getCapability('LIST-STATUS')) { + $lstatus = true; + $status_opts = ['MESSAGES', 'RECENT', 'UIDNEXT', 'UIDVALIDITY', 'UNSEEN', 'SIZE']; + $opts = array_diff($return_opts, $status_opts); + $status_opts = array_diff($return_opts, $opts); + + if (!empty($status_opts)) { + $rets[] = 'STATUS (' . implode(' ', $status_opts) . ')'; + } + + if (!empty($opts)) { + $rets = array_merge($rets, $opts); + } + } + + if (!empty($rets)) { + $args[] = 'RETURN (' . implode(' ', $rets) . ')'; + } + + list($code, $response) = $this->execute($subscribed ? 'LSUB' : 'LIST', $args); + + if ($code == self::ERROR_OK) { + $folders = []; + $last = 0; + $pos = 0; + $response .= "\r\n"; + + while ($pos = strpos($response, "\r\n", $pos+1)) { + // literal string, not real end-of-command-line + if ($response[$pos-1] == '}') { + continue; + } + + $line = substr($response, $last, $pos - $last); + $last = $pos + 2; + + if (!preg_match('/^\* (LIST|LSUB|STATUS|MYRIGHTS) /i', $line, $m)) { + continue; + } + + $cmd = strtoupper($m[1]); + $line = substr($line, strlen($m[0])); + + // * LIST () + if ($cmd == 'LIST' || $cmd == 'LSUB') { + list($opts, $delim, $mailbox) = $this->tokenizeResponse($line, 3); + + // Remove redundant separator at the end of folder name, UW-IMAP bug? (#1488879) + if ($delim) { + $mailbox = rtrim($mailbox, $delim); + } + + // Make it easier for the client to deal with INBOX folder + // by always returning the word with all capital letters + if (strlen($mailbox) == 5 + && ($mailbox[0] == 'i' || $mailbox[0] == 'I') + && ($mailbox[1] == 'n' || $mailbox[1] == 'N') + && ($mailbox[2] == 'b' || $mailbox[2] == 'B') + && ($mailbox[3] == 'o' || $mailbox[3] == 'O') + && ($mailbox[4] == 'x' || $mailbox[4] == 'X') + ) { + $mailbox = 'INBOX'; + } + + // Add to result array + if (!$lstatus) { + $folders[] = $mailbox; + } + else { + $folders[$mailbox] = []; + } + + // store folder options + if ($cmd == 'LIST') { + // Add to options array + if (empty($this->data['LIST'][$mailbox])) { + $this->data['LIST'][$mailbox] = $opts; + } + else if (!empty($opts)) { + $this->data['LIST'][$mailbox] = array_unique(array_merge( + $this->data['LIST'][$mailbox], $opts)); + } + } + } + else if ($lstatus) { + // * STATUS () + if ($cmd == 'STATUS') { + list($mailbox, $status) = $this->tokenizeResponse($line, 2); + + for ($i=0, $len=count($status); $i<$len; $i += 2) { + list($name, $value) = $this->tokenizeResponse($status, 2); + $folders[$mailbox][$name] = $value; + } + } + // * MYRIGHTS + else if ($cmd == 'MYRIGHTS') { + list($mailbox, $acl) = $this->tokenizeResponse($line, 2); + $folders[$mailbox]['MYRIGHTS'] = $acl; + } + } + } + + return $folders; + } + + return false; + } + + /** + * Returns count of all messages in a folder + * + * @param string $mailbox Mailbox name + * + * @return int Number of messages, False on error + */ + public function countMessages($mailbox) + { + if ($this->selected === $mailbox && isset($this->data['EXISTS'])) { + return $this->data['EXISTS']; + } + + // Check internal cache + if (!empty($this->data['STATUS:'.$mailbox])) { + $cache = $this->data['STATUS:'.$mailbox]; + if (isset($cache['MESSAGES'])) { + return (int) $cache['MESSAGES']; + } + } + + // Try STATUS (should be faster than SELECT) + $counts = $this->status($mailbox); + if (is_array($counts)) { + return (int) $counts['MESSAGES']; + } + + return false; + } + + /** + * Returns count of messages with \Recent flag in a folder + * + * @param string $mailbox Mailbox name + * + * @return int Number of messages, False on error + */ + public function countRecent($mailbox) + { + if ($this->selected === $mailbox && isset($this->data['RECENT'])) { + return $this->data['RECENT']; + } + + // Check internal cache + $cache = $this->data['STATUS:'.$mailbox]; + if (!empty($cache) && isset($cache['RECENT'])) { + return (int) $cache['RECENT']; + } + + // Try STATUS (should be faster than SELECT) + $counts = $this->status($mailbox, ['RECENT']); + if (is_array($counts)) { + return (int) $counts['RECENT']; + } + + return false; + } + + /** + * Returns count of messages without \Seen flag in a specified folder + * + * @param string $mailbox Mailbox name + * + * @return int Number of messages, False on error + */ + public function countUnseen($mailbox) + { + // Check internal cache + if (!empty($this->data['STATUS:'.$mailbox])) { + $cache = $this->data['STATUS:'.$mailbox]; + if (isset($cache['UNSEEN'])) { + return (int) $cache['UNSEEN']; + } + } + + // Try STATUS (should be faster than SELECT+SEARCH) + $counts = $this->status($mailbox); + if (is_array($counts)) { + return (int) $counts['UNSEEN']; + } + + // Invoke SEARCH as a fallback + $index = $this->search($mailbox, 'ALL UNSEEN', false, ['COUNT']); + if (!$index->is_error()) { + return $index->count(); + } + + return false; + } + + /** + * Executes ID command (RFC2971) + * + * @param array $items Client identification information key/value hash + * + * @return array|false Server identification information key/value hash, False on error + * @since 0.6 + */ + public function id($items = []) + { + if (is_array($items) && !empty($items)) { + foreach ($items as $key => $value) { + $args[] = $this->escape($key, true); + $args[] = $this->escape($value, true); + } + } + + list($code, $response) = $this->execute('ID', + [!empty($args) ? '(' . implode(' ', (array) $args) . ')' : $this->escape(null)], + 0, '/^\* ID /i' + ); + + if ($code == self::ERROR_OK && $response) { + $response = substr($response, 5); // remove prefix "* ID " + $items = $this->tokenizeResponse($response, 1); + $result = []; + + if (is_array($items)) { + for ($i=0, $len=count($items); $i<$len; $i += 2) { + $result[$items[$i]] = $items[$i+1]; + } + } + + return $result; + } + + return false; + } + + /** + * Executes ENABLE command (RFC5161) + * + * @param mixed $extension Extension name to enable (or array of names) + * + * @return array|bool List of enabled extensions, False on error + * @since 0.6 + */ + public function enable($extension) + { + if (empty($extension)) { + return false; + } + + if (!$this->hasCapability('ENABLE')) { + return false; + } + + if (!is_array($extension)) { + $extension = [$extension]; + } + + if (!empty($this->extensions_enabled)) { + // check if all extensions are already enabled + $diff = array_diff($extension, $this->extensions_enabled); + + if (empty($diff)) { + return $extension; + } + + // Make sure the mailbox isn't selected, before enabling extension(s) + if ($this->selected !== null) { + $this->close(); + } + } + + list($code, $response) = $this->execute('ENABLE', $extension, 0, '/^\* ENABLED /i'); + + if ($code == self::ERROR_OK && $response) { + $response = substr($response, 10); // remove prefix "* ENABLED " + $result = (array) $this->tokenizeResponse($response); + + $this->extensions_enabled = array_unique(array_merge((array)$this->extensions_enabled, $result)); + + return $this->extensions_enabled; + } + + return false; + } + + /** + * Executes SORT command + * + * @param string $mailbox Mailbox name + * @param string $field Field to sort by (ARRIVAL, CC, DATE, FROM, SIZE, SUBJECT, TO) + * @param string $criteria Searching criteria + * @param bool $return_uid Enables UID SORT usage + * @param string $encoding Character set + * + * @return rcube_result_index Response data + */ + public function sort($mailbox, $field = 'ARRIVAL', $criteria = '', $return_uid = false, $encoding = 'US-ASCII') + { + $old_sel = $this->selected; + $supported = ['ARRIVAL', 'CC', 'DATE', 'FROM', 'SIZE', 'SUBJECT', 'TO']; + $field = strtoupper($field); + + if ($field == 'INTERNALDATE') { + $field = 'ARRIVAL'; + } + + if (!in_array($field, $supported)) { + return new rcube_result_index($mailbox); + } + + if (!$this->select($mailbox)) { + return new rcube_result_index($mailbox); + } + + // return empty result when folder is empty and we're just after SELECT + if ($old_sel != $mailbox && empty($this->data['EXISTS'])) { + return new rcube_result_index($mailbox, '* SORT'); + } + + // RFC 5957: SORT=DISPLAY + if (($field == 'FROM' || $field == 'TO') && $this->getCapability('SORT=DISPLAY')) { + $field = 'DISPLAY' . $field; + } + + $encoding = $encoding ? trim($encoding) : 'US-ASCII'; + $criteria = $criteria ? 'ALL ' . trim($criteria) : 'ALL'; + + list($code, $response) = $this->execute($return_uid ? 'UID SORT' : 'SORT', + ["($field)", $encoding, $criteria]); + + if ($code != self::ERROR_OK) { + $response = null; + } + + return new rcube_result_index($mailbox, $response); + } + + /** + * Executes THREAD command + * + * @param string $mailbox Mailbox name + * @param string $algorithm Threading algorithm (ORDEREDSUBJECT, REFERENCES, REFS) + * @param string $criteria Searching criteria + * @param bool $return_uid Enables UIDs in result instead of sequence numbers + * @param string $encoding Character set + * + * @return rcube_result_thread Thread data + */ + public function thread($mailbox, $algorithm = 'REFERENCES', $criteria = '', $return_uid = false, $encoding = 'US-ASCII') + { + $old_sel = $this->selected; + + if (!$this->select($mailbox)) { + return new rcube_result_thread($mailbox); + } + + // return empty result when folder is empty and we're just after SELECT + if ($old_sel != $mailbox && !$this->data['EXISTS']) { + return new rcube_result_thread($mailbox, '* THREAD'); + } + + $encoding = $encoding ? trim($encoding) : 'US-ASCII'; + $algorithm = $algorithm ? trim($algorithm) : 'REFERENCES'; + $criteria = $criteria ? 'ALL '.trim($criteria) : 'ALL'; + + list($code, $response) = $this->execute($return_uid ? 'UID THREAD' : 'THREAD', + [$algorithm, $encoding, $criteria]); + + if ($code != self::ERROR_OK) { + $response = null; + } + + return new rcube_result_thread($mailbox, $response); + } + + /** + * Executes SEARCH command + * + * @param string $mailbox Mailbox name + * @param string $criteria Searching criteria + * @param bool $return_uid Enable UID in result instead of sequence ID + * @param array $items Return items (MIN, MAX, COUNT, ALL) + * + * @return rcube_result_index Result data + */ + public function search($mailbox, $criteria, $return_uid = false, $items = []) + { + $old_sel = $this->selected; + + if (!$this->select($mailbox)) { + return new rcube_result_index($mailbox); + } + + // return empty result when folder is empty and we're just after SELECT + if ($old_sel != $mailbox && !$this->data['EXISTS']) { + return new rcube_result_index($mailbox, '* SEARCH'); + } + + // If ESEARCH is supported always use ALL + // but not when items are specified or using simple id2uid search + if (empty($items) && preg_match('/[^0-9]/', $criteria)) { + $items = ['ALL']; + } + + $esearch = empty($items) ? false : $this->getCapability('ESEARCH'); + $criteria = trim($criteria); + $params = ''; + + // RFC4731: ESEARCH + if (!empty($items) && $esearch) { + $params .= 'RETURN (' . implode(' ', $items) . ')'; + } + + if (!empty($criteria)) { + $params .= ($params ? ' ' : '') . $criteria; + } + else { + $params .= 'ALL'; + } + + list($code, $response) = $this->execute($return_uid ? 'UID SEARCH' : 'SEARCH', [$params]); + + if ($code != self::ERROR_OK) { + $response = null; + } + + return new rcube_result_index($mailbox, $response); + } + + /** + * Simulates SORT command by using FETCH and sorting. + * + * @param string $mailbox Mailbox name + * @param string|array $message_set Searching criteria (list of messages to return) + * @param string $index_field Field to sort by (ARRIVAL, CC, DATE, FROM, SIZE, SUBJECT, TO) + * @param bool $skip_deleted Makes that DELETED messages will be skipped + * @param bool $uidfetch Enables UID FETCH usage + * @param bool $return_uid Enables returning UIDs instead of IDs + * + * @return rcube_result_index Response data + */ + public function index($mailbox, $message_set, $index_field = '', $skip_deleted = true, + $uidfetch = false, $return_uid = false) + { + $msg_index = $this->fetchHeaderIndex($mailbox, $message_set, + $index_field, $skip_deleted, $uidfetch, $return_uid); + + if (!empty($msg_index)) { + asort($msg_index); // ASC + $msg_index = array_keys($msg_index); + $msg_index = '* SEARCH ' . implode(' ', $msg_index); + } + else { + $msg_index = is_array($msg_index) ? '* SEARCH' : null; + } + + return new rcube_result_index($mailbox, $msg_index); + } + + /** + * Fetches specified header/data value for a set of messages. + * + * @param string $mailbox Mailbox name + * @param string|array $message_set Searching criteria (list of messages to return) + * @param string $index_field Field to sort by (ARRIVAL, CC, DATE, FROM, SIZE, SUBJECT, TO) + * @param bool $skip_deleted Makes that DELETED messages will be skipped + * @param bool $uidfetch Enables UID FETCH usage + * @param bool $return_uid Enables returning UIDs instead of IDs + * + * @return array|bool List of header values or False on failure + */ + public function fetchHeaderIndex($mailbox, $message_set, $index_field = '', $skip_deleted = true, + $uidfetch = false, $return_uid = false) + { + // Validate input + if (is_array($message_set)) { + if (!($message_set = $this->compressMessageSet($message_set))) { + return false; + } + } + else if (empty($message_set)) { + return false; + } + else if (strpos($message_set, ':')) { + list($from_idx, $to_idx) = explode(':', $message_set); + if ($to_idx != '*' && (int) $from_idx > (int) $to_idx) { + return false; + } + } + + $index_field = empty($index_field) ? 'DATE' : strtoupper($index_field); + + $supported = [ + 'DATE' => 1, + 'INTERNALDATE' => 4, + 'ARRIVAL' => 4, + 'FROM' => 1, + 'REPLY-TO' => 1, + 'SENDER' => 1, + 'TO' => 1, + 'CC' => 1, + 'SUBJECT' => 1, + 'UID' => 2, + 'SIZE' => 2, + 'SEEN' => 3, + 'RECENT' => 3, + 'DELETED' => 3, + ]; + + if (empty($supported[$index_field])) { + return false; + } + + $mode = $supported[$index_field]; + + // Select the mailbox + if (!$this->select($mailbox)) { + return false; + } + + // build FETCH command string + $key = $this->nextTag(); + $cmd = $uidfetch ? 'UID FETCH' : 'FETCH'; + $fields = []; + + if ($return_uid) { + $fields[] = 'UID'; + } + if ($skip_deleted) { + $fields[] = 'FLAGS'; + } + + if ($mode == 1) { + if ($index_field == 'DATE') { + $fields[] = 'INTERNALDATE'; + } + $fields[] = "BODY.PEEK[HEADER.FIELDS ($index_field)]"; + } + else if ($mode == 2) { + if ($index_field == 'SIZE') { + $fields[] = 'RFC822.SIZE'; + } + else if (!$return_uid || $index_field != 'UID') { + $fields[] = $index_field; + } + } + else if ($mode == 3 && !$skip_deleted) { + $fields[] = 'FLAGS'; + } + else if ($mode == 4) { + $fields[] = 'INTERNALDATE'; + } + + $request = "$key $cmd $message_set (" . implode(' ', $fields) . ")"; + + if (!$this->putLine($request)) { + $this->setError(self::ERROR_COMMAND, "Failed to send $cmd command"); + return false; + } + + $result = []; + + do { + $line = rtrim($this->readLine(200)); + $line = $this->multLine($line); + + if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) { + $id = $m[1]; + $flags = null; + + if ($return_uid) { + if (preg_match('/UID ([0-9]+)/', $line, $matches)) { + $id = (int) $matches[1]; + } + else { + continue; + } + } + + if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { + $flags = explode(' ', strtoupper($matches[1])); + if (in_array('\\DELETED', $flags)) { + continue; + } + } + + if ($mode == 1 && $index_field == 'DATE') { + if (preg_match('/BODY\[HEADER\.FIELDS \("*DATE"*\)\] (.*)/', $line, $matches)) { + $value = preg_replace(['/^"*[a-z]+:/i'], '', $matches[1]); + $value = trim($value); + $result[$id] = rcube_utils::strtotime($value); + } + // non-existent/empty Date: header, use INTERNALDATE + if (empty($result[$id])) { + if (preg_match('/INTERNALDATE "([^"]+)"/', $line, $matches)) { + $result[$id] = rcube_utils::strtotime($matches[1]); + } + else { + $result[$id] = 0; + } + } + } + else if ($mode == 1) { + if (preg_match('/BODY\[HEADER\.FIELDS \("?(FROM|REPLY-TO|SENDER|TO|SUBJECT)"?\)\] (.*)/', $line, $matches)) { + $value = preg_replace(['/^"*[a-z]+:/i', '/\s+$/sm'], ['', ''], $matches[2]); + $result[$id] = trim($value); + } + else { + $result[$id] = ''; + } + } + else if ($mode == 2) { + if (preg_match('/' . $index_field . ' ([0-9]+)/', $line, $matches)) { + $result[$id] = trim($matches[1]); + } + else { + $result[$id] = 0; + } + } + else if ($mode == 3) { + if (!$flags && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { + $flags = explode(' ', $matches[1]); + } + $result[$id] = in_array("\\".$index_field, (array) $flags) ? 1 : 0; + } + else if ($mode == 4) { + if (preg_match('/INTERNALDATE "([^"]+)"/', $line, $matches)) { + $result[$id] = rcube_utils::strtotime($matches[1]); + } + else { + $result[$id] = 0; + } + } + } + } + while (!$this->startsWith($line, $key, true, true)); + + return $result; + } + + /** + * Returns message sequence identifier + * + * @param string $mailbox Mailbox name + * @param int $uid Message unique identifier (UID) + * + * @return int Message sequence identifier + */ + public function UID2ID($mailbox, $uid) + { + if ($uid > 0) { + $index = $this->search($mailbox, "UID $uid"); + + if ($index->count() == 1) { + $arr = $index->get(); + return (int) $arr[0]; + } + } + } + + /** + * Returns message unique identifier (UID) + * + * @param string $mailbox Mailbox name + * @param int $id Message sequence identifier + * + * @return int Message unique identifier + */ + public function ID2UID($mailbox, $id) + { + if (empty($id) || $id < 0) { + return null; + } + + if (!$this->select($mailbox)) { + return null; + } + + if (!empty($this->data['UID-MAP'][$id])) { + return $this->data['UID-MAP'][$id]; + } + + if (isset($this->data['EXISTS']) && $id > $this->data['EXISTS']) { + return null; + } + + $index = $this->search($mailbox, $id, true); + + if ($index->count() == 1) { + $arr = $index->get(); + return $this->data['UID-MAP'][$id] = (int) $arr[0]; + } + } + + /** + * Sets flag of the message(s) + * + * @param string $mailbox Mailbox name + * @param string|array $messages Message UID(s) + * @param string $flag Flag name + * + * @return bool True on success, False on failure + */ + public function flag($mailbox, $messages, $flag) + { + return $this->modFlag($mailbox, $messages, $flag, '+'); + } + + /** + * Unsets flag of the message(s) + * + * @param string $mailbox Mailbox name + * @param string|array $messages Message UID(s) + * @param string $flag Flag name + * + * @return bool True on success, False on failure + */ + public function unflag($mailbox, $messages, $flag) + { + return $this->modFlag($mailbox, $messages, $flag, '-'); + } + + /** + * Changes flag of the message(s) + * + * @param string $mailbox Mailbox name + * @param string|array $messages Message UID(s) + * @param string $flag Flag name + * @param string $mod Modifier [+|-]. Default: "+". + * + * @return bool True on success, False on failure + */ + protected function modFlag($mailbox, $messages, $flag, $mod = '+') + { + if (!$flag) { + return false; + } + + if (!$this->select($mailbox)) { + return false; + } + + if (empty($this->data['READ-WRITE'])) { + $this->setError(self::ERROR_READONLY, "Mailbox is read-only"); + return false; + } + + if (!empty($this->flags[strtoupper($flag)])) { + $flag = $this->flags[strtoupper($flag)]; + } + + // if PERMANENTFLAGS is not specified all flags are allowed + if (!empty($this->data['PERMANENTFLAGS']) + && !in_array($flag, (array) $this->data['PERMANENTFLAGS']) + && !in_array('\\*', (array) $this->data['PERMANENTFLAGS']) + ) { + return false; + } + + // Clear internal status cache + if ($flag == 'SEEN') { + unset($this->data['STATUS:'.$mailbox]['UNSEEN']); + } + + if ($mod != '+' && $mod != '-') { + $mod = '+'; + } + + $result = $this->execute('UID STORE', + [$this->compressMessageSet($messages), $mod . 'FLAGS.SILENT', "($flag)"], + self::COMMAND_NORESPONSE + ); + + return $result == self::ERROR_OK; + } + + /** + * Copies message(s) from one folder to another + * + * @param string|array $messages Message UID(s) + * @param string $from Mailbox name + * @param string $to Destination mailbox name + * + * @return bool True on success, False on failure + */ + public function copy($messages, $from, $to) + { + // Clear last COPYUID data + unset($this->data['COPYUID']); + + if (!$this->select($from)) { + return false; + } + + // Clear internal status cache + unset($this->data['STATUS:'.$to]); + + $result = $this->execute('UID COPY', + [$this->compressMessageSet($messages), $this->escape($to)], + self::COMMAND_NORESPONSE + ); + + return $result == self::ERROR_OK; + } + + /** + * Moves message(s) from one folder to another. + * + * @param string|array $messages Message UID(s) + * @param string $from Mailbox name + * @param string $to Destination mailbox name + * + * @return bool True on success, False on failure + */ + public function move($messages, $from, $to) + { + if (!$this->select($from)) { + return false; + } + + if (empty($this->data['READ-WRITE'])) { + $this->setError(self::ERROR_READONLY, "Mailbox is read-only"); + return false; + } + + // use MOVE command (RFC 6851) + if ($this->hasCapability('MOVE')) { + // Clear last COPYUID data + unset($this->data['COPYUID']); + + // Clear internal status cache + unset($this->data['STATUS:'.$to]); + $this->clear_status_cache($from); + + $result = $this->execute('UID MOVE', + [$this->compressMessageSet($messages), $this->escape($to)], + self::COMMAND_NORESPONSE + ); + + return $result == self::ERROR_OK; + } + + // use COPY + STORE +FLAGS.SILENT \Deleted + EXPUNGE + $result = $this->copy($messages, $from, $to); + + if ($result) { + // Clear internal status cache + unset($this->data['STATUS:'.$from]); + + $result = $this->flag($from, $messages, 'DELETED'); + + if ($messages == '*') { + // CLOSE+SELECT should be faster than EXPUNGE + $this->close(); + } + else { + $this->expunge($from, $messages); + } + } + + return $result; + } + + /** + * FETCH command (RFC3501) + * + * @param string $mailbox Mailbox name + * @param mixed $message_set Message(s) sequence identifier(s) or UID(s) + * @param bool $is_uid True if $message_set contains UIDs + * @param array $query_items FETCH command data items + * @param string $mod_seq Modification sequence for CHANGEDSINCE (RFC4551) query + * @param bool $vanished Enables VANISHED parameter (RFC5162) for CHANGEDSINCE query + * + * @return array List of rcube_message_header elements, False on error + * @since 0.6 + */ + public function fetch($mailbox, $message_set, $is_uid = false, $query_items = [], + $mod_seq = null, $vanished = false) + { + if (!$this->select($mailbox)) { + return false; + } + + $message_set = $this->compressMessageSet($message_set); + $result = []; + + $key = $this->nextTag(); + $cmd = ($is_uid ? 'UID ' : '') . 'FETCH'; + $request = "$key $cmd $message_set (" . implode(' ', $query_items) . ")"; + + if ($mod_seq !== null && $this->hasCapability('CONDSTORE')) { + $request .= " (CHANGEDSINCE $mod_seq" . ($vanished ? " VANISHED" : '') .")"; + } + + if (!$this->putLine($request)) { + $this->setError(self::ERROR_COMMAND, "Failed to send $cmd command"); + return false; + } + + do { + $line = $this->readFullLine(4096); + + if (!$line) { + break; + } + + // Sample reply line: + // * 321 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen) + // INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODYSTRUCTURE (...) + // BODY[HEADER.FIELDS ... + + if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) { + $id = intval($m[1]); + + $result[$id] = new rcube_message_header; + $result[$id]->id = $id; + $result[$id]->subject = ''; + $result[$id]->messageID = 'mid:' . $id; + + $headers = null; + $line = substr($line, strlen($m[0]) + 2); + + // Tokenize response and assign to object properties + while (($tokens = $this->tokenizeResponse($line, 2)) && count($tokens) == 2) { + list($name, $value) = $tokens; + if ($name == 'UID') { + $result[$id]->uid = intval($value); + } + else if ($name == 'RFC822.SIZE') { + $result[$id]->size = intval($value); + } + else if ($name == 'RFC822.TEXT') { + $result[$id]->body = $value; + } + else if ($name == 'INTERNALDATE') { + $result[$id]->internaldate = $value; + $result[$id]->date = $value; + $result[$id]->timestamp = rcube_utils::strtotime($value); + } + else if ($name == 'FLAGS') { + if (!empty($value)) { + foreach ((array)$value as $flag) { + $flag = str_replace(['$', "\\"], '', $flag); + $flag = strtoupper($flag); + + $result[$id]->flags[$flag] = true; + } + } + } + else if ($name == 'MODSEQ') { + $result[$id]->modseq = $value[0]; + } + else if ($name == 'ENVELOPE') { + $result[$id]->envelope = $value; + } + else if ($name == 'BODYSTRUCTURE' || ($name == 'BODY' && count($value) > 2)) { + if (!is_array($value[0]) && (strtolower($value[0]) == 'message' && strtolower($value[1]) == 'rfc822')) { + $value = [$value]; + } + $result[$id]->bodystructure = $value; + } + else if ($name == 'RFC822') { + $result[$id]->body = $value; + } + else if (stripos($name, 'BODY[') === 0) { + $name = str_replace(']', '', substr($name, 5)); + + if ($name == 'HEADER.FIELDS') { + // skip ']' after headers list + $this->tokenizeResponse($line, 1); + $headers = $this->tokenizeResponse($line, 1); + } + else if (strlen($name)) { + $result[$id]->bodypart[$name] = $value; + } + else { + $result[$id]->body = $value; + } + } + } + + // create array with header field:data + if (!empty($headers)) { + $headers = explode("\n", trim($headers)); + $lines = []; + $ln = 0; + + foreach ($headers as $resln) { + if (!isset($resln[0]) || ord($resln[0]) <= 32) { + $lines[$ln] = ($lines[$ln] ?? '') . (empty($lines[$ln]) ? '' : "\n") . trim($resln); + } + else { + $lines[++$ln] = trim($resln); + } + } + + foreach ($lines as $str) { + if (strpos($str, ':') === false) { + continue; + } + + list($field, $string) = explode(':', $str, 2); + + $field = strtolower($field); + $string = preg_replace('/\n[\t\s]*/', ' ', trim($string)); + + switch ($field) { + case 'date'; + $string = substr($string, 0, 128); + $result[$id]->date = $string; + $result[$id]->timestamp = rcube_utils::strtotime($string); + break; + case 'to': + $result[$id]->to = preg_replace('/undisclosed-recipients:[;,]*/', '', $string); + break; + case 'from': + case 'subject': + $string = substr($string, 0, 2048); + case 'cc': + case 'bcc': + case 'references': + $result[$id]->{$field} = $string; + break; + case 'reply-to': + $result[$id]->replyto = $string; + break; + case 'content-transfer-encoding': + $result[$id]->encoding = substr($string, 0, 32); + break; + case 'content-type': + $ctype_parts = preg_split('/[; ]+/', $string); + $result[$id]->ctype = strtolower(array_shift($ctype_parts)); + if (preg_match('/charset\s*=\s*"?([a-z0-9\-\.\_]+)"?/i', $string, $regs)) { + $result[$id]->charset = $regs[1]; + } + break; + case 'in-reply-to': + $result[$id]->in_reply_to = str_replace(["\n", '<', '>'], '', $string); + break; + case 'disposition-notification-to': + case 'x-confirm-reading-to': + $result[$id]->mdn_to = substr($string, 0, 2048); + break; + case 'message-id': + $result[$id]->messageID = substr($string, 0, 2048); + break; + case 'x-priority': + if (preg_match('/^(\d+)/', $string, $matches)) { + $result[$id]->priority = intval($matches[1]); + } + break; + default: + if (strlen($field) < 3) { + break; + } + if (!empty($result[$id]->others[$field])) { + $string = array_merge((array) $result[$id]->others[$field], (array) $string); + } + $result[$id]->others[$field] = $string; + } + } + } + } + // VANISHED response (QRESYNC RFC5162) + // Sample: * VANISHED (EARLIER) 300:310,405,411 + else if (preg_match('/^\* VANISHED [()EARLIER]*/i', $line, $match)) { + $line = substr($line, strlen($match[0])); + $v_data = $this->tokenizeResponse($line, 1); + + $this->data['VANISHED'] = $v_data; + } + } + while (!$this->startsWith($line, $key, true)); + + return $result; + } + + /** + * Returns message(s) data (flags, headers, etc.) + * + * @param string $mailbox Mailbox name + * @param mixed $message_set Message(s) sequence identifier(s) or UID(s) + * @param bool $is_uid True if $message_set contains UIDs + * @param bool $bodystr Enable to add BODYSTRUCTURE data to the result + * @param array $add_headers List of additional headers + * + * @return bool|array List of rcube_message_header elements, False on error + */ + public function fetchHeaders($mailbox, $message_set, $is_uid = false, $bodystr = false, $add_headers = []) + { + $query_items = ['UID', 'RFC822.SIZE', 'FLAGS', 'INTERNALDATE']; + $headers = ['DATE', 'FROM', 'TO', 'SUBJECT', 'CONTENT-TYPE', 'CC', 'REPLY-TO', + 'LIST-POST', 'DISPOSITION-NOTIFICATION-TO', 'X-PRIORITY']; + + if (!empty($add_headers)) { + $add_headers = array_map('strtoupper', $add_headers); + $headers = array_unique(array_merge($headers, $add_headers)); + } + + if ($bodystr) { + $query_items[] = 'BODYSTRUCTURE'; + } + + $query_items[] = 'BODY.PEEK[HEADER.FIELDS (' . implode(' ', $headers) . ')]'; + + return $this->fetch($mailbox, $message_set, $is_uid, $query_items); + } + + /** + * Returns message data (flags, headers, etc.) + * + * @param string $mailbox Mailbox name + * @param int $id Message sequence identifier or UID + * @param bool $is_uid True if $id is an UID + * @param bool $bodystr Enable to add BODYSTRUCTURE data to the result + * @param array $add_headers List of additional headers + * + * @return bool|rcube_message_header Message data, False on error + */ + public function fetchHeader($mailbox, $id, $is_uid = false, $bodystr = false, $add_headers = []) + { + $a = $this->fetchHeaders($mailbox, $id, $is_uid, $bodystr, $add_headers); + + if (is_array($a)) { + return array_shift($a); + } + + return false; + } + + /** + * Sort messages by specified header field + * + * @param array $messages Array of rcube_message_header objects + * @param string $field Name of the property to sort by + * @param string $order Sorting order (ASC|DESC) + * + * @return array Sorted input array + */ + public static function sortHeaders($messages, $field, $order = 'ASC') + { + $field = empty($field) ? 'uid' : strtolower($field); + $order = empty($order) ? 'ASC' : strtoupper($order); + $index = []; + + reset($messages); + + // Create an index + foreach ($messages as $key => $headers) { + switch ($field) { + case 'arrival': + $field = 'internaldate'; + // no-break + case 'date': + case 'internaldate': + case 'timestamp': + $value = rcube_utils::strtotime($headers->$field); + if (!$value && $field != 'timestamp') { + $value = $headers->timestamp; + } + + break; + + default: + // @TODO: decode header value, convert to UTF-8 + $value = $headers->$field; + if (is_string($value)) { + $value = str_replace('"', '', $value); + + if ($field == 'subject') { + $value = rcube_utils::remove_subject_prefix($value); + } + } + } + + $index[$key] = $value; + } + + $sort_order = $order == 'ASC' ? SORT_ASC : SORT_DESC; + $sort_flags = SORT_STRING | SORT_FLAG_CASE; + + if (in_array($field, ['arrival', 'date', 'internaldate', 'timestamp', 'size', 'uid', 'id'])) { + $sort_flags = SORT_NUMERIC; + } + + array_multisort($index, $sort_order, $sort_flags, $messages); + + return $messages; + } + + /** + * Fetch MIME headers of specified message parts + * + * @param string $mailbox Mailbox name + * @param int $uid Message UID + * @param array $parts Message part identifiers + * @param bool $mime Use MIME instead of HEADER + * + * @return array|bool Array containing headers string for each specified body + * False on failure. + */ + public function fetchMIMEHeaders($mailbox, $uid, $parts, $mime = true) + { + if (!$this->select($mailbox)) { + return false; + } + + $parts = (array) $parts; + $key = $this->nextTag(); + $peeks = []; + $type = $mime ? 'MIME' : 'HEADER'; + + // format request + foreach ($parts as $part) { + $peeks[] = "BODY.PEEK[$part.$type]"; + } + + $request = "$key UID FETCH $uid (" . implode(' ', $peeks) . ')'; + + // send request + if (!$this->putLine($request)) { + $this->setError(self::ERROR_COMMAND, "Failed to send UID FETCH command"); + return false; + } + + $result = []; + + do { + $line = $this->readLine(1024); + if (preg_match('/^\* [0-9]+ FETCH [0-9UID( ]+/', $line, $m)) { + $line = ltrim(substr($line, strlen($m[0]))); + while (preg_match('/^\s*BODY\[([0-9\.]+)\.'.$type.'\]/', $line, $matches)) { + $line = substr($line, strlen($matches[0])); + $result[$matches[1]] = trim($this->multLine($line)); + $line = $this->readLine(1024); + } + } + } + while (!$this->startsWith($line, $key, true)); + + return $result; + } + + /** + * Fetches message part header + */ + public function fetchPartHeader($mailbox, $id, $is_uid = false, $part = null) + { + $part = empty($part) ? 'HEADER' : $part.'.MIME'; + + return $this->handlePartBody($mailbox, $id, $is_uid, $part); + } + + /** + * Fetches body of the specified message part + */ + public function handlePartBody($mailbox, $id, $is_uid = false, $part = '', $encoding = null, $print = null, + $file = null, $formatted = false, $max_bytes = 0) + { + if (!$this->select($mailbox)) { + return false; + } + + $binary = true; + $initiated = false; + + do { + if (!$initiated) { + switch ($encoding) { + case 'base64': + $mode = 1; + break; + case 'quoted-printable': + $mode = 2; + break; + case 'x-uuencode': + case 'x-uue': + case 'uue': + case 'uuencode': + $mode = 3; + break; + default: + $mode = $formatted ? 4 : 0; + } + + // Use BINARY extension when possible (and safe) + $binary = $binary && $mode && preg_match('/^[0-9.]+$/', (string) $part) && $this->hasCapability('BINARY'); + $fetch_mode = $binary ? 'BINARY' : 'BODY'; + $partial = $max_bytes ? sprintf('<0.%d>', $max_bytes) : ''; + + // format request + $key = $this->nextTag(); + $cmd = ($is_uid ? 'UID ' : '') . 'FETCH'; + $request = "$key $cmd $id ($fetch_mode.PEEK[$part]$partial)"; + $result = false; + $found = false; + $initiated = true; + + // send request + if (!$this->putLine($request)) { + $this->setError(self::ERROR_COMMAND, "Failed to send $cmd command"); + return false; + } + + if ($binary) { + // WARNING: Use $formatted argument with care, this may break binary data stream + $mode = -1; + } + } + + $line = trim($this->readLine(1024)); + + if (!$line) { + break; + } + + // handle UNKNOWN-CTE response - RFC 3516, try again with standard BODY request + if ($binary && !$found && preg_match('/^' . $key . ' NO \[(UNKNOWN-CTE|PARSE)\]/i', $line)) { + $binary = $initiated = false; + continue; + } + + // skip irrelevant untagged responses (we have a result already) + if ($found || !preg_match('/^\* ([0-9]+) FETCH (.*)$/', $line, $m)) { + continue; + } + + $line = $m[2]; + + // handle one line response + if ($line[0] == '(' && substr($line, -1) == ')') { + // tokenize content inside brackets + // the content can be e.g.: (UID 9844 BODY[2.4] NIL) + $line = preg_replace('/(^\(|\)$)/', '', $line); + $tokens = $this->tokenizeResponse($line); + + for ($i=0; $ireadLine(1024)); // the OK response line + continue; + } + + if ($result !== false) { + $result = $this->decodeContent($result, $mode, true); + } + } + // response with string literal + else if (preg_match('/\{([0-9]+)\}$/', $line, $m)) { + $bytes = (int) $m[1]; + $prev = ''; + $found = true; + $chunkSize = 1024 * 1024; + + // empty body + if (!$bytes) { + $result = ''; + } + // An optimal path for a case when we need the body as-is in a string + else if (!$mode && !$file && !$print) { + $result = $this->readBytes($bytes); + } + else while ($bytes > 0) { + $chunk = $this->readBytes($bytes > $chunkSize ? $chunkSize : $bytes); + + if ($chunk === '') { + break; + } + + $len = strlen($chunk); + + if ($len > $bytes) { + $chunk = substr($chunk, 0, $bytes); + $len = strlen($chunk); + } + $bytes -= $len; + + $chunk = $this->decodeContent($chunk, $mode, $bytes <= 0, $prev); + + if ($file) { + if (fwrite($file, $chunk) === false) { + break; + } + } + else if ($print) { + echo $chunk; + } + else { + $result .= $chunk; + } + } + } + } + while (!$this->startsWith($line, $key, true) || !$initiated); + + if ($result !== false) { + if ($file) { + return fwrite($file, $result); + } + else if ($print) { + echo $result; + return true; + } + + return $result; + } + + return false; + } + + /** + * Decodes a chunk of a message part content from a FETCH response. + * + * @param string $chunk Content + * @param int $mode Encoding mode + * @param bool $is_last Whether it is a last chunk of data + * @param string $prev Extra content from the previous chunk + * + * @return string Encoded string + */ + protected static function decodeContent($chunk, $mode, $is_last = false, &$prev = '') + { + // BASE64 + if ($mode == 1) { + $chunk = $prev . preg_replace('|[^a-zA-Z0-9+=/]|', '', $chunk); + + // create chunks with proper length for base64 decoding + $length = strlen($chunk); + + if ($length % 4) { + $length = floor($length / 4) * 4; + $prev = substr($chunk, $length); + $chunk = substr($chunk, 0, $length); + } + else { + $prev = ''; + } + + return base64_decode($chunk); + } + + // QUOTED-PRINTABLE + if ($mode == 2) { + if (!self::decodeContentChunk($chunk, $prev, $is_last)) { + return ''; + } + + $chunk = preg_replace('/[\t\r\0\x0B]+\n/', "\n", $chunk); + + return quoted_printable_decode($chunk); + } + + // X-UUENCODE + if ($mode == 3) { + if (!self::decodeContentChunk($chunk, $prev, $is_last)) { + return ''; + } + + $chunk = preg_replace( + ['/\r?\n/', '/(^|\n)end$/', '/^begin\s+[0-7]{3,4}\s+[^\n]+\n/'], + ["\n", '', ''], + $chunk + ); + + if (!strlen($chunk)) { + return ''; + } + + return convert_uudecode($chunk); + } + + // Plain text formatted + // TODO: Formatting should be handled outside of this class + if ($mode == 4) { + if (!self::decodeContentChunk($chunk, $prev, $is_last)) { + return ''; + } + + if ($is_last) { + $chunk = rtrim($chunk, "\t\r\n\0\x0B"); + } + + return preg_replace('/[\t\r\0\x0B]+\n/', "\n", $chunk); + } + + return $chunk; + } + + /** + * A helper for a new-line aware parsing. See self::decodeContent(). + */ + private static function decodeContentChunk(&$chunk, &$prev, $is_last) + { + $chunk = $prev . $chunk; + $prev = ''; + + if (!$is_last) { + if (($pos = strrpos($chunk, "\n")) !== false) { + $prev = substr($chunk, $pos + 1); + $chunk = substr($chunk, 0, $pos + 1); + } else { + $prev = $chunk; + return false; + } + } + + return true; + } + + /** + * Handler for IMAP APPEND command + * + * @param string $mailbox Mailbox name + * @param string|array $message The message source string or array (of strings and file pointers) + * @param array $flags Message flags + * @param string $date Message internal date + * @param bool $binary Enable BINARY append (RFC3516) + * + * @return string|bool On success APPENDUID response (if available) or True, False on failure + */ + public function append($mailbox, &$message, $flags = [], $date = null, $binary = false) + { + unset($this->data['APPENDUID']); + + if ($mailbox === null || $mailbox === '') { + return false; + } + + $binary = $binary && $this->getCapability('BINARY'); + $literal_plus = !$binary && !empty($this->prefs['literal+']); + $len = 0; + $msg = is_array($message) ? $message : [&$message]; + $chunk_size = 512000; + + for ($i=0, $cnt=count($msg); $i<$cnt; $i++) { + if (is_resource($msg[$i])) { + $stat = fstat($msg[$i]); + if ($stat === false) { + return false; + } + $len += $stat['size']; + } + else { + if (!$binary) { + $msg[$i] = str_replace("\r", '', $msg[$i]); + $msg[$i] = str_replace("\n", "\r\n", $msg[$i]); + } + + $len += strlen($msg[$i]); + } + } + + if (!$len) { + return false; + } + + // build APPEND command + $key = $this->nextTag(); + $request = "$key APPEND " . $this->escape($mailbox) . ' (' . $this->flagsToStr($flags) . ')'; + if (!empty($date)) { + $request .= ' ' . $this->escape($date); + } + $request .= ' ' . ($binary ? '~' : '') . '{' . $len . ($literal_plus ? '+' : '') . '}'; + + // send APPEND command + if (!$this->putLine($request)) { + $this->setError(self::ERROR_COMMAND, "Failed to send APPEND command"); + return false; + } + + // Do not wait when LITERAL+ is supported + if (!$literal_plus) { + $line = $this->readReply(); + + if ($line[0] != '+') { + $this->parseResult($line, 'APPEND: '); + return false; + } + } + + foreach ($msg as $msg_part) { + // file pointer + if (is_resource($msg_part)) { + rewind($msg_part); + while (!feof($msg_part) && $this->fp) { + $buffer = fread($msg_part, $chunk_size); + $this->putLine($buffer, false); + } + fclose($msg_part); + } + // string + else { + $size = strlen($msg_part); + + // Break up the data by sending one chunk (up to 512k) at a time. + // This approach reduces our peak memory usage + for ($offset = 0; $offset < $size; $offset += $chunk_size) { + $chunk = substr($msg_part, $offset, $chunk_size); + if (!$this->putLine($chunk, false)) { + return false; + } + } + } + } + + if (!$this->putLine('')) { // \r\n + return false; + } + + do { + $line = $this->readLine(); + } while (!$this->startsWith($line, $key, true, true)); + + // Clear internal status cache + unset($this->data['STATUS:'.$mailbox]); + + if ($this->parseResult($line, 'APPEND: ') != self::ERROR_OK) { + return false; + } + + if (!empty($this->data['APPENDUID'])) { + return $this->data['APPENDUID']; + } + + return true; + } + + /** + * Handler for IMAP APPEND command. + * + * @param string $mailbox Mailbox name + * @param string $path Path to the file with message body + * @param string $headers Message headers + * @param array $flags Message flags + * @param string $date Message internal date + * @param bool $binary Enable BINARY append (RFC3516) + * + * @return string|bool On success APPENDUID response (if available) or True, False on failure + */ + public function appendFromFile($mailbox, $path, $headers = null, $flags = [], $date = null, $binary = false) + { + // open message file + if (file_exists(realpath($path))) { + $fp = fopen($path, 'r'); + } + + if (empty($fp)) { + $this->setError(self::ERROR_UNKNOWN, "Couldn't open $path for reading"); + return false; + } + + $message = []; + if ($headers) { + $message[] = trim($headers, "\r\n") . "\r\n\r\n"; + } + $message[] = $fp; + + return $this->append($mailbox, $message, $flags, $date, $binary); + } + + /** + * Returns QUOTA information + * + * @param string $mailbox Mailbox name + * + * @return array|false Quota information, False on error + */ + public function getQuota($mailbox = null) + { + if ($mailbox === null || $mailbox === '') { + $mailbox = 'INBOX'; + } + + // a0001 GETQUOTAROOT INBOX + // * QUOTAROOT INBOX user/sample + // * QUOTA user/sample (STORAGE 654 9765) + // a0001 OK Completed + + list($code, $response) = $this->execute('GETQUOTAROOT', [$this->escape($mailbox)], 0, '/^\* QUOTA /i'); + + if ($code != self::ERROR_OK) { + return false; + } + + $min_free = PHP_INT_MAX; + $result = []; + $all = []; + + foreach (explode("\n", $response) as $line) { + $tokens = $this->tokenizeResponse($line, 3); + $quota_root = $tokens[2] ?? null; + $quotas = $this->tokenizeResponse($line, 1); + + if (empty($quotas)) { + continue; + } + + foreach (array_chunk($quotas, 3) as $quota) { + list($type, $used, $total) = $quota; + $type = strtolower($type); + + if ($type && $total) { + $all[$quota_root][$type]['used'] = intval($used); + $all[$quota_root][$type]['total'] = intval($total); + } + } + + if (empty($all[$quota_root]['storage'])) { + continue; + } + + $used = $all[$quota_root]['storage']['used']; + $total = $all[$quota_root]['storage']['total']; + $free = $total - $used; + + // calculate lowest available space from all storage quotas + if ($free < $min_free) { + $min_free = $free; + $result['used'] = $used; + $result['total'] = $total; + $result['percent'] = min(100, round(($used/max(1,$total))*100)); + $result['free'] = 100 - $result['percent']; + } + } + + if (!empty($result)) { + $result['all'] = $all; + } + + return $result; + } + + /** + * Send the SETACL command (RFC4314) + * + * @param string $mailbox Mailbox name + * @param string $user User name + * @param mixed $acl ACL string or array + * + * @return bool True on success, False on failure + * + * @since 0.5-beta + */ + public function setACL($mailbox, $user, $acl) + { + if (is_array($acl)) { + $acl = implode('', $acl); + } + + $result = $this->execute('SETACL', + [$this->escape($mailbox), $this->escape($user), strtolower($acl)], + self::COMMAND_NORESPONSE + ); + + return $result == self::ERROR_OK; + } + + /** + * Send the DELETEACL command (RFC4314) + * + * @param string $mailbox Mailbox name + * @param string $user User name + * + * @return bool True on success, False on failure + * + * @since 0.5-beta + */ + public function deleteACL($mailbox, $user) + { + $result = $this->execute('DELETEACL', + [$this->escape($mailbox), $this->escape($user)], + self::COMMAND_NORESPONSE + ); + + return $result == self::ERROR_OK; + } + + /** + * Send the GETACL command (RFC4314) + * + * @param string $mailbox Mailbox name + * + * @return array User-rights array on success, NULL on error + * @since 0.5-beta + */ + public function getACL($mailbox) + { + list($code, $response) = $this->execute('GETACL', [$this->escape($mailbox)], 0, '/^\* ACL /i'); + + if ($code == self::ERROR_OK && $response) { + // Parse server response (remove "* ACL ") + $response = substr($response, 6); + $ret = $this->tokenizeResponse($response); + $mbox = array_shift($ret); + $size = count($ret); + + // Create user-rights hash array + // @TODO: consider implementing fixACL() method according to RFC4314.2.1.1 + // so we could return only standard rights defined in RFC4314, + // excluding 'c' and 'd' defined in RFC2086. + if ($size % 2 == 0) { + for ($i=0; $i<$size; $i++) { + $ret[$ret[$i]] = str_split($ret[++$i]); + unset($ret[$i-1]); + unset($ret[$i]); + } + return $ret; + } + + $this->setError(self::ERROR_COMMAND, "Incomplete ACL response"); + } + } + + /** + * Send the LISTRIGHTS command (RFC4314) + * + * @param string $mailbox Mailbox name + * @param string $user User name + * + * @return array List of user rights + * @since 0.5-beta + */ + public function listRights($mailbox, $user) + { + list($code, $response) = $this->execute('LISTRIGHTS', + [$this->escape($mailbox), $this->escape($user)], 0, '/^\* LISTRIGHTS /i'); + + if ($code == self::ERROR_OK && $response) { + // Parse server response (remove "* LISTRIGHTS ") + $response = substr($response, 13); + + $ret_mbox = $this->tokenizeResponse($response, 1); + $ret_user = $this->tokenizeResponse($response, 1); + $granted = $this->tokenizeResponse($response, 1); + $optional = trim($response); + + return [ + 'granted' => str_split($granted), + 'optional' => explode(' ', $optional), + ]; + } + } + + /** + * Send the MYRIGHTS command (RFC4314) + * + * @param string $mailbox Mailbox name + * + * @return array MYRIGHTS response on success, NULL on error + * @since 0.5-beta + */ + public function myRights($mailbox) + { + list($code, $response) = $this->execute('MYRIGHTS', [$this->escape($mailbox)], 0, '/^\* MYRIGHTS /i'); + + if ($code == self::ERROR_OK && $response) { + // Parse server response (remove "* MYRIGHTS ") + $response = substr($response, 11); + + $ret_mbox = $this->tokenizeResponse($response, 1); + $rights = $this->tokenizeResponse($response, 1); + + return str_split($rights); + } + } + + /** + * Send the SETMETADATA command (RFC5464) + * + * @param string $mailbox Mailbox name + * @param array $entries Entry-value array (use NULL value as NIL) + * + * @return bool True on success, False on failure + * @since 0.5-beta + */ + public function setMetadata($mailbox, $entries) + { + if (!is_array($entries) || empty($entries)) { + $this->setError(self::ERROR_COMMAND, "Wrong argument for SETMETADATA command"); + return false; + } + + foreach ($entries as $name => $value) { + $entries[$name] = $this->escape($name) . ' ' . $this->escape($value, true); + } + + $entries = implode(' ', $entries); + $result = $this->execute('SETMETADATA', + [$this->escape($mailbox), '(' . $entries . ')'], + self::COMMAND_NORESPONSE + ); + + return $result == self::ERROR_OK; + } + + /** + * Send the SETMETADATA command with NIL values (RFC5464) + * + * @param string $mailbox Mailbox name + * @param array $entries Entry names array + * + * @return bool True on success, False on failure + * + * @since 0.5-beta + */ + public function deleteMetadata($mailbox, $entries) + { + if (!is_array($entries) && !empty($entries)) { + $entries = explode(' ', $entries); + } + + if (empty($entries)) { + $this->setError(self::ERROR_COMMAND, "Wrong argument for SETMETADATA command"); + return false; + } + + $data = []; + foreach ($entries as $entry) { + $data[$entry] = null; + } + + return $this->setMetadata($mailbox, $data); + } + + /** + * Send the GETMETADATA command (RFC5464) + * + * @param string $mailbox Mailbox name + * @param array $entries Entries + * @param array $options Command options (with MAXSIZE and DEPTH keys) + * + * @return array GETMETADATA result on success, NULL on error + * + * @since 0.5-beta + */ + public function getMetadata($mailbox, $entries, $options = []) + { + if (!is_array($entries)) { + $entries = [$entries]; + } + + $args = []; + + // create options string + if (is_array($options)) { + $options = array_change_key_case($options, CASE_UPPER); + $opts = []; + + if (!empty($options['MAXSIZE'])) { + $opts[] = 'MAXSIZE '.intval($options['MAXSIZE']); + } + + if (isset($options['DEPTH'])) { + $opts[] = 'DEPTH ' . $this->escape($options['DEPTH']); + } + + if (!empty($opts)) { + $args[] = $opts; + } + } + + $args[] = $this->escape($mailbox); + $args[] = array_map([$this, 'escape'], $entries); + + list($code, $response) = $this->execute('GETMETADATA', $args); + + if ($code == self::ERROR_OK) { + $result = []; + $data = $this->tokenizeResponse($response); + + // The METADATA response can contain multiple entries in a single + // response or multiple responses for each entry or group of entries + for ($i = 0, $size = count($data); $i < $size; $i++) { + if ($data[$i] === '*' + && $data[++$i] === 'METADATA' + && is_string($mbox = $data[++$i]) + && is_array($data[++$i]) + ) { + for ($x = 0, $size2 = count($data[$i]); $x < $size2; $x += 2) { + if ($data[$i][$x+1] !== null) { + $result[$mbox][$data[$i][$x]] = $data[$i][$x+1]; + } + } + } + } + + return $result; + } + } + + /** + * Send the SETANNOTATION command (draft-daboo-imap-annotatemore) + * + * @param string $mailbox Mailbox name + * @param array $data Data array where each item is an array with + * three elements: entry name, attribute name, value + * + * @return bool True on success, False on failure + * @since 0.5-beta + */ + public function setAnnotation($mailbox, $data) + { + if (!is_array($data) || empty($data)) { + $this->setError(self::ERROR_COMMAND, "Wrong argument for SETANNOTATION command"); + return false; + } + + foreach ($data as $entry) { + // ANNOTATEMORE drafts before version 08 require quoted parameters + $entries[] = sprintf('%s (%s %s)', $this->escape($entry[0], true), + $this->escape($entry[1], true), $this->escape($entry[2], true)); + } + + $entries = implode(' ', $entries); + $result = $this->execute('SETANNOTATION', [$this->escape($mailbox), $entries], self::COMMAND_NORESPONSE); + + return $result == self::ERROR_OK; + } + + /** + * Send the SETANNOTATION command with NIL values (draft-daboo-imap-annotatemore) + * + * @param string $mailbox Mailbox name + * @param array $data Data array where each item is an array with + * two elements: entry name and attribute name + * + * @return bool True on success, False on failure + * + * @since 0.5-beta + */ + public function deleteAnnotation($mailbox, $data) + { + if (!is_array($data) || empty($data)) { + $this->setError(self::ERROR_COMMAND, "Wrong argument for SETANNOTATION command"); + return false; + } + + return $this->setAnnotation($mailbox, $data); + } + + /** + * Send the GETANNOTATION command (draft-daboo-imap-annotatemore) + * + * @param string $mailbox Mailbox name + * @param array $entries Entries names + * @param array $attribs Attribs names + * + * @return array Annotations result on success, NULL on error + * + * @since 0.5-beta + */ + public function getAnnotation($mailbox, $entries, $attribs) + { + if (!is_array($entries)) { + $entries = [$entries]; + } + + // create entries string + // ANNOTATEMORE drafts before version 08 require quoted parameters + foreach ($entries as $idx => $name) { + $entries[$idx] = $this->escape($name, true); + } + $entries = '(' . implode(' ', $entries) . ')'; + + if (!is_array($attribs)) { + $attribs = [$attribs]; + } + + // create attributes string + foreach ($attribs as $idx => $name) { + $attribs[$idx] = $this->escape($name, true); + } + $attribs = '(' . implode(' ', $attribs) . ')'; + + list($code, $response) = $this->execute('GETANNOTATION', [$this->escape($mailbox), $entries, $attribs]); + + if ($code == self::ERROR_OK) { + $result = []; + $data = $this->tokenizeResponse($response); + $last_entry = null; + + // Here we returns only data compatible with METADATA result format + if (!empty($data) && ($size = count($data))) { + for ($i=0; $i<$size; $i++) { + $entry = $data[$i]; + if (isset($mbox) && is_array($entry)) { + $attribs = $entry; + $entry = $last_entry; + } + else if ($entry == '*') { + if ($data[$i+1] == 'ANNOTATION') { + $mbox = $data[$i+2]; + unset($data[$i]); // "*" + unset($data[++$i]); // "ANNOTATION" + unset($data[++$i]); // Mailbox + } + // get rid of other untagged responses + else { + unset($mbox); + unset($data[$i]); + } + continue; + } + else if (isset($mbox)) { + $attribs = $data[++$i]; + } + else { + unset($data[$i]); + continue; + } + + if (!empty($attribs)) { + for ($x=0, $len=count($attribs); $x<$len;) { + $attr = $attribs[$x++]; + $value = $attribs[$x++]; + if ($attr == 'value.priv' && $value !== null) { + $result[$mbox]['/private' . $entry] = $value; + } + else if ($attr == 'value.shared' && $value !== null) { + $result[$mbox]['/shared' . $entry] = $value; + } + } + } + + $last_entry = $entry; + unset($data[$i]); + } + } + + return $result; + } + } + + /** + * Returns BODYSTRUCTURE for the specified message. + * + * @param string $mailbox Folder name + * @param int $id Message sequence number or UID + * @param bool $is_uid True if $id is an UID + * + * @return array|bool Body structure array or False on error. + * @since 0.6 + */ + public function getStructure($mailbox, $id, $is_uid = false) + { + $result = $this->fetch($mailbox, $id, $is_uid, ['BODYSTRUCTURE']); + + if (is_array($result) && !empty($result)) { + $result = array_shift($result); + return $result->bodystructure; + } + + return false; + } + + /** + * Returns data of a message part according to specified structure. + * + * @param array $structure Message structure (getStructure() result) + * @param string $part Message part identifier + * + * @return array Part data as hash array (type, encoding, charset, size) + */ + public static function getStructurePartData($structure, $part) + { + $part_a = self::getStructurePartArray($structure, $part); + $data = []; + + if (empty($part_a)) { + return $data; + } + + // content-type + if (is_array($part_a[0])) { + $data['type'] = 'multipart'; + } + else { + $data['type'] = strtolower($part_a[0]); + $data['subtype'] = strtolower($part_a[1]); + $data['encoding'] = strtolower($part_a[5]); + + // charset + if (is_array($part_a[2])) { + foreach ($part_a[2] as $key => $val) { + if (strcasecmp($val, 'charset') == 0) { + $data['charset'] = $part_a[2][$key+1]; + break; + } + } + } + } + + // size + $data['size'] = intval($part_a[6]); + + return $data; + } + + public static function getStructurePartArray($a, $part) + { + if (!is_array($a)) { + return false; + } + + if (empty($part)) { + return $a; + } + + $ctype = is_string($a[0]) && is_string($a[1]) ? $a[0] . '/' . $a[1] : ''; + + if (strcasecmp($ctype, 'message/rfc822') == 0) { + $a = $a[8]; + } + + if (strpos($part, '.') > 0) { + $orig_part = $part; + $pos = strpos($part, '.'); + $rest = substr($orig_part, $pos+1); + $part = substr($orig_part, 0, $pos); + + return self::getStructurePartArray($a[$part-1], $rest); + } + else if ($part > 0) { + return is_array($a[$part-1]) ? $a[$part-1] : $a; + } + } + + /** + * Creates next command identifier (tag) + * + * @return string Command identifier + * @since 0.5-beta + */ + public function nextTag() + { + $this->cmd_num++; + $this->cmd_tag = sprintf('A%04d', $this->cmd_num); + + return $this->cmd_tag; + } + + /** + * Sends IMAP command and parses result + * + * @param string $command IMAP command + * @param array $arguments Command arguments + * @param int $options Execution options + * @param string $filter Line filter (regexp) + * + * @return mixed Response code or list of response code and data + * @since 0.5-beta + */ + public function execute($command, $arguments = [], $options = 0, $filter = null) + { + $tag = $this->nextTag(); + $query = $tag . ' ' . $command; + $noresp = ($options & self::COMMAND_NORESPONSE); + $response = $noresp ? null : ''; + + if (!empty($arguments)) { + foreach ($arguments as $arg) { + $query .= ' ' . self::r_implode($arg); + } + } + + // Send command + if (!$this->putLineC($query, true, ($options & self::COMMAND_ANONYMIZED))) { + preg_match('/^[A-Z0-9]+ ((UID )?[A-Z]+)/', $query, $matches); + $cmd = $matches[1] ?: 'UNKNOWN'; + $this->setError(self::ERROR_COMMAND, "Failed to send $cmd command"); + + return $noresp ? self::ERROR_COMMAND : [self::ERROR_COMMAND, '']; + } + + // Parse response + do { + $line = $this->readFullLine(4096); + + if ($response !== null) { + if (!$filter || preg_match($filter, $line)) { + $response .= $line; + } + } + + // parse untagged response for [COPYUID 1204196876 3456:3457 123:124] (RFC6851) + if ($line && $command == 'UID MOVE') { + if (preg_match("/^\* OK \[COPYUID [0-9]+ ([0-9,:]+) ([0-9,:]+)\]/i", $line, $m)) { + $this->data['COPYUID'] = [$m[1], $m[2]]; + } + } + } + while (!$this->startsWith($line, $tag . ' ', true, true)); + + $code = $this->parseResult($line, $command . ': '); + + // Remove last line from response + if ($response) { + if (!$filter) { + $line_len = min(strlen($response), strlen($line)); + $response = substr($response, 0, -$line_len); + } + + $response = rtrim($response, "\r\n"); + } + + // optional CAPABILITY response + if (($options & self::COMMAND_CAPABILITY) && $code == self::ERROR_OK + && preg_match('/\[CAPABILITY ([^]]+)\]/i', $line, $matches) + ) { + $this->parseCapability($matches[1], true); + } + + // return last line only (without command tag, result and response code) + if ($line && ($options & self::COMMAND_LASTLINE)) { + $response = preg_replace("/^$tag (OK|NO|BAD|BYE|PREAUTH)?\s*(\[[a-z-]+\])?\s*/i", '', trim($line)); + } + + return $noresp ? $code : [$code, $response]; + } + + /** + * Splits IMAP response into string tokens + * + * @param string &$str The IMAP's server response + * @param int $num Number of tokens to return + * + * @return mixed Tokens array or string if $num=1 + * @since 0.5-beta + */ + public static function tokenizeResponse(&$str, $num=0) + { + $result = []; + + while (!$num || count($result) < $num) { + // remove spaces from the beginning of the string + $str = ltrim($str); + + // empty string + if ($str === '' || $str === null) { + break; + } + + switch ($str[0]) { + + // String literal + case '{': + if (($epos = strpos($str, "}\r\n", 1)) == false) { + // error + } + if (!is_numeric(($bytes = substr($str, 1, $epos - 1)))) { + // error + } + + $result[] = $bytes ? substr($str, $epos + 3, $bytes) : ''; + $str = substr($str, $epos + 3 + $bytes); + break; + + // Quoted string + case '"': + $len = strlen($str); + + for ($pos=1; $pos<$len; $pos++) { + if ($str[$pos] == '"') { + break; + } + if ($str[$pos] == "\\") { + if ($str[$pos + 1] == '"' || $str[$pos + 1] == "\\") { + $pos++; + } + } + } + + // we need to strip slashes for a quoted string + $result[] = stripslashes(substr($str, 1, $pos - 1)); + $str = substr($str, $pos + 1); + break; + + // Parenthesized list + case '(': + $str = substr($str, 1); + $result[] = self::tokenizeResponse($str); + break; + + case ')': + $str = substr($str, 1); + return $result; + + // String atom, number, astring, NIL, *, % + default: + // excluded chars: SP, CTL, ), DEL + // we do not exclude [ and ] (#1489223) + if (preg_match('/^([^\x00-\x20\x29\x7F]+)/', $str, $m)) { + $result[] = $m[1] == 'NIL' ? null : $m[1]; + $str = substr($str, strlen($m[1])); + } + + break; + } + } + + return $num == 1 ? ($result[0] ?? '') : $result; + } + + /** + * Joins IMAP command line elements (recursively) + */ + protected static function r_implode($element) + { + if (!is_array($element)) { + return $element; + } + + reset($element); + + $string = ''; + + foreach ($element as $value) { + $string .= ' ' . self::r_implode($value); + } + + return '(' . trim($string) . ')'; + } + + /** + * Converts message identifiers array into sequence-set syntax + * + * @param array $messages Message identifiers + * @param bool $force Forces compression of any size + * + * @return string Compressed sequence-set + */ + public static function compressMessageSet($messages, $force = false) + { + // given a comma delimited list of independent mid's, + // compresses by grouping sequences together + if (!is_array($messages)) { + // if less than 255 bytes long, let's not bother + if (!$force && strlen($messages) < 255) { + return preg_match('/[^0-9:,*]/', $messages) ? 'INVALID' : $messages; + } + + // see if it's already been compressed + if (strpos($messages, ':') !== false) { + return preg_match('/[^0-9:,*]/', $messages) ? 'INVALID' : $messages; + } + + // separate, then sort + $messages = explode(',', $messages); + } + + sort($messages); + + $result = []; + $start = $prev = $messages[0]; + + foreach ($messages as $id) { + $incr = $id - $prev; + if ($incr > 1) { // found a gap + if ($start == $prev) { + $result[] = $prev; // push single id + } + else { + $result[] = $start . ':' . $prev; // push sequence as start_id:end_id + } + $start = $id; // start of new sequence + } + $prev = $id; + } + + // handle the last sequence/id + if ($start == $prev) { + $result[] = $prev; + } + else { + $result[] = $start.':'.$prev; + } + + // return as comma separated string + $result = implode(',', $result); + + return preg_match('/[^0-9:,*]/', $result) ? 'INVALID' : $result; + } + + /** + * Converts message sequence-set into array + * + * @param string $messages Message identifiers + * + * @return array List of message identifiers + */ + public static function uncompressMessageSet($messages) + { + if (empty($messages)) { + return []; + } + + $result = []; + $messages = explode(',', $messages); + + foreach ($messages as $idx => $part) { + $items = explode(':', $part); + + if (!empty($items[1]) && $items[1] > $items[0]) { + $max = $items[1]; + } + else { + $max = $items[0]; + } + + for ($x = $items[0]; $x <= $max; $x++) { + $result[] = (int) $x; + } + + unset($messages[$idx]); + } + + return $result; + } + + /** + * Clear internal status cache + */ + protected function clear_status_cache($mailbox) + { + unset($this->data['STATUS:' . $mailbox]); + + $keys = ['EXISTS', 'RECENT', 'UNSEEN', 'UID-MAP']; + + foreach ($keys as $key) { + unset($this->data[$key]); + } + } + + /** + * Clear internal cache of the current mailbox + */ + protected function clear_mailbox_cache() + { + $this->clear_status_cache($this->selected); + + $keys = ['UIDNEXT', 'UIDVALIDITY', 'HIGHESTMODSEQ', 'NOMODSEQ', + 'PERMANENTFLAGS', 'QRESYNC', 'VANISHED', 'READ-WRITE']; + + foreach ($keys as $key) { + unset($this->data[$key]); + } + } + + /** + * Converts flags array into string for inclusion in IMAP command + * + * @param array $flags Flags (see self::flags) + * + * @return string Space-separated list of flags + */ + protected function flagsToStr($flags) + { + foreach ((array) $flags as $idx => $flag) { + if ($flag = $this->flags[strtoupper($flag)]) { + $flags[$idx] = $flag; + } + } + + return implode(' ', (array) $flags); + } + + /** + * CAPABILITY response parser + */ + protected function parseCapability($str, $trusted=false) + { + $str = preg_replace('/^\* CAPABILITY /i', '', $str); + + $this->capability = explode(' ', strtoupper($str)); + + if (!empty($this->prefs['disabled_caps'])) { + $this->capability = array_diff($this->capability, $this->prefs['disabled_caps']); + } + + if (!isset($this->prefs['literal+']) && in_array('LITERAL+', $this->capability)) { + $this->prefs['literal+'] = true; + } + else if (!isset($this->prefs['literal-']) && in_array('LITERAL-', $this->capability)) { + $this->prefs['literal-'] = true; + } + + if ($trusted) { + $this->capability_read = true; + } + } + + /** + * Escapes a string when it contains special characters (RFC3501) + * + * @param string $string IMAP string + * @param bool $force_quotes Forces string quoting (for atoms) + * + * @return string String atom, quoted-string or string literal + * @todo lists + */ + public static function escape($string, $force_quotes = false) + { + if ($string === null) { + return 'NIL'; + } + + if ($string === '') { + return '""'; + } + + // atom-string (only safe characters) + if (!$force_quotes && !preg_match('/[\x00-\x20\x22\x25\x28-\x2A\x5B-\x5D\x7B\x7D\x80-\xFF]/', $string)) { + return $string; + } + + // quoted-string + if (!preg_match('/[\r\n\x00\x80-\xFF]/', $string)) { + return '"' . addcslashes($string, '\\"') . '"'; + } + + // literal-string + return sprintf("{%d}\r\n%s", strlen($string), $string); + } + + /** + * Set the value of the debugging flag. + * + * @param bool $debug New value for the debugging flag. + * @param callable $handler Logging handler function + * + * @since 0.5-stable + */ + public function setDebug($debug, $handler = null) + { + $this->debug = $debug; + $this->debug_handler = $handler; + } + + /** + * Write the given debug text to the current debug output handler. + * + * @param string $message Debug message text. + * + * @since 0.5-stable + */ + protected function debug($message) + { + if (($len = strlen($message)) > self::DEBUG_LINE_LENGTH) { + $diff = $len - self::DEBUG_LINE_LENGTH; + $message = substr($message, 0, self::DEBUG_LINE_LENGTH) + . "... [truncated $diff bytes]"; + } + + if ($this->resourceid) { + $message = sprintf('[%s] %s', $this->resourceid, $message); + } + + if ($this->debug_handler) { + call_user_func_array($this->debug_handler, [$this, $message]); + } + else { + echo "DEBUG: $message\n"; + } + } +} diff --git a/admin/tool/messageinbound/roundcube/rcube_message_header.php b/admin/tool/messageinbound/roundcube/rcube_message_header.php new file mode 100644 index 00000000000..28b95fa69b3 --- /dev/null +++ b/admin/tool/messageinbound/roundcube/rcube_message_header.php @@ -0,0 +1,430 @@ + | + +-----------------------------------------------------------------------+ +*/ + +/** + * Struct representing an e-mail message header + * + * @package Framework + * @subpackage Storage + */ +class rcube_message_header +{ + /** + * Message sequence number + * + * @var int + */ + public $id; + + /** + * Message unique identifier + * + * @var int + */ + public $uid; + + /** + * Message subject + * + * @var string + */ + public $subject; + + /** + * Message sender (From) + * + * @var string + */ + public $from; + + /** + * Message recipient (To) + * + * @var string + */ + public $to; + + /** + * Message additional recipients (Cc) + * + * @var string + */ + public $cc; + + /** + * Message hidden recipients (Bcc) + * + * @var string + */ + public $bcc; + + /** + * Message Reply-To header + * + * @var string + */ + public $replyto; + + /** + * Message In-Reply-To header + * + * @var string + */ + public $in_reply_to; + + /** + * Message date (Date) + * + * @var string + */ + public $date; + + /** + * Message identifier (Message-ID) + * + * @var string + */ + public $messageID; + + /** + * Message size + * + * @var int + */ + public $size; + + /** + * Message encoding + * + * @var string + */ + public $encoding; + + /** + * Message charset + * + * @var string + */ + public $charset; + + /** + * Message Content-type + * + * @var string + */ + public $ctype; + + /** + * Message timestamp (based on message date) + * + * @var int + */ + public $timestamp; + + /** + * IMAP bodystructure string + * + * @var string + */ + public $bodystructure; + + /** + * IMAP body (RFC822.TEXT) + * + * @var string + */ + public $body; + + /** + * IMAP part bodies + * + * @var array + */ + public $bodypart = []; + + /** + * IMAP internal date + * + * @var string + */ + public $internaldate; + + /** + * Message References header + * + * @var string + */ + public $references; + + /** + * Message priority (X-Priority) + * + * @var int + */ + public $priority; + + /** + * Message receipt recipient + * + * @var string + */ + public $mdn_to; + + /** + * IMAP folder this message is stored in + * + * @var string + */ + public $folder; + + /** + * Other message headers + * + * @var array + */ + public $others = []; + + /** + * Message flags + * + * @var array + */ + public $flags = []; + + /** + * Extra flags (for the messages list) + * + * @var array + * @deprecated Use $flags + */ + public $list_flags = []; + + /** + * Extra columns content (for the messages list) + * + * @var array + */ + public $list_cols = []; + + /** + * Message structure + * + * @var rcube_message_part + */ + public $structure; + + /** + * Message thread depth + * + * @var int + */ + public $depth; + + /** + * Whether the message has references in the thread + * + * @var bool + */ + public $has_children; + + /** + * Number of flagged children (in a thread) + * + * @var int + */ + public $flagged_children; + + /** + * Number of unread children (in a thread) + * + * @var int + */ + public $unread_children; + + /** + * UID of the message parent (in a thread) + * + * @var int + */ + public $parent_uid; + + /** + * IMAP MODSEQ value + * + * @var int + */ + public $modseq; + + /** + * IMAP ENVELOPE + * + * @var string + */ + public $envelope; + + /** + * Header name to rcube_message_header object property map + * + * @var array + */ + private $obj_headers = [ + 'date' => 'date', + 'from' => 'from', + 'to' => 'to', + 'subject' => 'subject', + 'reply-to' => 'replyto', + 'cc' => 'cc', + 'bcc' => 'bcc', + 'mbox' => 'folder', + 'folder' => 'folder', + 'content-transfer-encoding' => 'encoding', + 'in-reply-to' => 'in_reply_to', + 'content-type' => 'ctype', + 'charset' => 'charset', + 'references' => 'references', + 'disposition-notification-to' => 'mdn_to', + 'x-confirm-reading-to' => 'mdn_to', + 'message-id' => 'messageID', + 'x-priority' => 'priority', + ]; + + /** + * Returns header value + * + * @param string $name Header name + * @param bool $decode Decode the header content + * + * @return string|null Header content + */ + public function get($name, $decode = true) + { + $name = strtolower($name); + $value = null; + + if (isset($this->obj_headers[$name]) && isset($this->{$this->obj_headers[$name]})) { + $value = $this->{$this->obj_headers[$name]}; + } + else if (isset($this->others[$name])) { + $value = $this->others[$name]; + } + + if ($decode && $value !== null) { + if (is_array($value)) { + foreach ($value as $key => $val) { + $val = rcube_mime::decode_header($val, $this->charset); + $value[$key] = rcube_charset::clean($val); + } + } + else { + $value = rcube_mime::decode_header($value, $this->charset); + $value = rcube_charset::clean($value); + } + } + + return $value; + } + + /** + * Sets header value + * + * @param string $name Header name + * @param string $value Header content + */ + public function set($name, $value) + { + $name = strtolower($name); + + if (isset($this->obj_headers[$name])) { + $this->{$this->obj_headers[$name]} = $value; + } + else { + $this->others[$name] = $value; + } + } + + /** + * Factory method to instantiate headers from a data array + * + * @param array $arr Hash array with header values + * + * @return rcube_message_header instance filled with headers values + */ + public static function from_array($arr) + { + $obj = new rcube_message_header; + foreach ($arr as $k => $v) { + $obj->set($k, $v); + } + + return $obj; + } +} + + +/** + * Class for sorting an array of rcube_message_header objects in a predetermined order. + * + * @package Framework + * @subpackage Storage + */ +class rcube_message_header_sorter +{ + /** @var array Message UIDs */ + private $uids = []; + + + /** + * Set the predetermined sort order. + * + * @param array $index Numerically indexed array of IMAP UIDs + */ + function set_index($index) + { + $index = array_flip($index); + + $this->uids = $index; + } + + /** + * Sort the array of header objects + * + * @param array $headers Array of rcube_message_header objects indexed by UID + */ + function sort_headers(&$headers) + { + uksort($headers, [$this, "compare_uids"]); + } + + /** + * Sort method called by uksort() + * + * @param int $a Array key (UID) + * @param int $b Array key (UID) + */ + function compare_uids($a, $b) + { + // then find each sequence number in my ordered list + $posa = isset($this->uids[$a]) ? intval($this->uids[$a]) : -1; + $posb = isset($this->uids[$b]) ? intval($this->uids[$b]) : -1; + + // return the relative position as the comparison value + return $posa - $posb; + } +} diff --git a/admin/tool/messageinbound/roundcube/rcube_mime.php b/admin/tool/messageinbound/roundcube/rcube_mime.php new file mode 100644 index 00000000000..d0b2cbca80c --- /dev/null +++ b/admin/tool/messageinbound/roundcube/rcube_mime.php @@ -0,0 +1,992 @@ + | + | Author: Aleksander Machniak | + +-----------------------------------------------------------------------+ +*/ + +/** + * Class for parsing MIME messages + * + * @package Framework + * @subpackage Storage + */ +class rcube_mime +{ + private static $default_charset; + + + /** + * Object constructor. + */ + function __construct($default_charset = null) + { + self::$default_charset = $default_charset; + } + + /** + * Returns message/object character set name + * + * @return string Character set name + */ + public static function get_charset() + { + if (self::$default_charset) { + return self::$default_charset; + } + + if ($charset = rcube::get_instance()->config->get('default_charset')) { + return $charset; + } + + return RCUBE_CHARSET; + } + + /** + * Parse the given raw message source and return a structure + * of rcube_message_part objects. + * + * It makes use of the rcube_mime_decode library + * + * @param string $raw_body The message source + * + * @return object rcube_message_part The message structure + */ + public static function parse_message($raw_body) + { + $conf = [ + 'include_bodies' => true, + 'decode_bodies' => true, + 'decode_headers' => false, + 'default_charset' => self::get_charset(), + ]; + + $mime = new rcube_mime_decode($conf); + + return $mime->decode($raw_body); + } + + /** + * Split an address list into a structured array list + * + * @param string|array $input Input string (or list of strings) + * @param int $max List only this number of addresses + * @param bool $decode Decode address strings + * @param string $fallback Fallback charset if none specified + * @param bool $addronly Return flat array with e-mail addresses only + * + * @return array Indexed list of addresses + */ + static function decode_address_list($input, $max = null, $decode = true, $fallback = null, $addronly = false) + { + // A common case when the same header is used many times in a mail message + if (is_array($input)) { + $input = implode(', ', $input); + } + + $a = self::parse_address_list((string) $input, $decode, $fallback); + $out = []; + $j = 0; + + // Special chars as defined by RFC 822 need to in quoted string (or escaped). + $special_chars = '[\(\)\<\>\\\.\[\]@,;:"]'; + + if (!is_array($a)) { + return $out; + } + + foreach ($a as $val) { + $j++; + $address = trim($val['address']); + + if ($addronly) { + $out[$j] = $address; + } + else { + $name = trim($val['name']); + $string = ''; + + if ($name && $address && $name != $address) { + $string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address); + } + else if ($address) { + $string = $address; + } + else if ($name) { + $string = $name; + } + + $out[$j] = ['name' => $name, 'mailto' => $address, 'string' => $string]; + } + + if ($max && $j == $max) { + break; + } + } + + return $out; + } + + /** + * Decode a message header value + * + * @param string $input Header value + * @param string $fallback Fallback charset if none specified + * + * @return string Decoded string + */ + public static function decode_header($input, $fallback = null) + { + $str = self::decode_mime_string((string)$input, $fallback); + + return $str; + } + + /** + * Decode a mime-encoded string to internal charset + * + * @param string $input Header value + * @param string $fallback Fallback charset if none specified + * + * @return string Decoded string + */ + public static function decode_mime_string($input, $fallback = null) + { + $default_charset = $fallback ?: self::get_charset(); + + // rfc: all line breaks or other characters not found + // in the Base64 Alphabet must be ignored by decoding software + // delete all blanks between MIME-lines, differently we can + // receive unnecessary blanks and broken utf-8 symbols + $input = preg_replace("/\?=\s+=\?/", '?==?', $input); + + // encoded-word regexp + $re = '/=\?([^?]+)\?([BbQq])\?([^\n]*?)\?=/'; + + // Find all RFC2047's encoded words + if (preg_match_all($re, $input, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { + // Initialize variables + $tmp = []; + $out = ''; + $start = 0; + + foreach ($matches as $idx => $m) { + $pos = $m[0][1]; + $charset = $m[1][0]; + $encoding = $m[2][0]; + $text = $m[3][0]; + $length = strlen($m[0][0]); + + // Append everything that is before the text to be decoded + if ($start != $pos) { + $substr = substr($input, $start, $pos-$start); + $out .= rcube_charset::convert($substr, $default_charset); + $start = $pos; + } + $start += $length; + + // Per RFC2047, each string part "MUST represent an integral number + // of characters . A multi-octet character may not be split across + // adjacent encoded-words." However, some mailers break this, so we + // try to handle characters spanned across parts anyway by iterating + // through and aggregating sequential encoded parts with the same + // character set and encoding, then perform the decoding on the + // aggregation as a whole. + + $tmp[] = $text; + if (!empty($matches[$idx+1]) && ($next_match = $matches[$idx+1])) { + if ($next_match[0][1] == $start + && $next_match[1][0] == $charset + && $next_match[2][0] == $encoding + ) { + continue; + } + } + + $count = count($tmp); + $text = ''; + + // Decode and join encoded-word's chunks + if ($encoding == 'B' || $encoding == 'b') { + $rest = ''; + // base64 must be decoded a segment at a time. + // However, there are broken implementations that continue + // in the following word, we'll handle that (#6048) + for ($i=0; $i<$count; $i++) { + $chunk = $rest . $tmp[$i]; + $length = strlen($chunk); + if ($length % 4) { + $length = floor($length / 4) * 4; + $rest = substr($chunk, $length); + $chunk = substr($chunk, 0, $length); + } + + $text .= base64_decode($chunk); + } + } + else { // if ($encoding == 'Q' || $encoding == 'q') { + // quoted printable can be combined and processed at once + for ($i=0; $i<$count; $i++) { + $text .= $tmp[$i]; + } + + $text = str_replace('_', ' ', $text); + $text = quoted_printable_decode($text); + } + + $out .= rcube_charset::convert($text, $charset); + $tmp = []; + } + + // add the last part of the input string + if ($start != strlen($input)) { + $out .= rcube_charset::convert(substr($input, $start), $default_charset); + } + + // return the results + return $out; + } + + // no encoding information, use fallback + return rcube_charset::convert($input, $default_charset); + } + + /** + * Decode a mime part + * + * @param string $input Input string + * @param string $encoding Part encoding + * + * @return string Decoded string + */ + public static function decode($input, $encoding = '7bit') + { + switch (strtolower($encoding)) { + case 'quoted-printable': + return quoted_printable_decode($input); + case 'base64': + return base64_decode($input); + case 'x-uuencode': + case 'x-uue': + case 'uue': + case 'uuencode': + return convert_uudecode($input); + case '7bit': + default: + return $input; + } + } + + /** + * Split RFC822 header string into an associative array + */ + public static function parse_headers($headers) + { + $result = []; + $headers = preg_replace('/\r?\n(\t| )+/', ' ', $headers); + $lines = explode("\n", $headers); + $count = count($lines); + + for ($i=0; $i<$count; $i++) { + if ($p = strpos($lines[$i], ': ')) { + $field = strtolower(substr($lines[$i], 0, $p)); + $value = trim(substr($lines[$i], $p+1)); + if (!empty($value)) { + $result[$field] = $value; + } + } + } + + return $result; + } + + /** + * E-mail address list parser + */ + private static function parse_address_list($str, $decode = true, $fallback = null) + { + // remove any newlines and carriage returns before + $str = preg_replace('/\r?\n(\s|\t)?/', ' ', $str); + + // extract list items, remove comments + $str = self::explode_header_string(',;', $str, true); + + // simplified regexp, supporting quoted local part + $email_rx = '([^\s:]+|("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+"))@\S+'; + + $result = []; + + foreach ($str as $key => $val) { + $name = ''; + $address = ''; + $val = trim($val); + + // First token might be a group name, ignore it + $tokens = self::explode_header_string(' ', $val); + if (isset($tokens[0]) && $tokens[0][strlen($tokens[0])-1] == ':') { + $val = substr($val, strlen($tokens[0])); + } + + if (preg_match('/(.*)<('.$email_rx.')$/', $val, $m)) { + // Note: There are cases like "Test'); + $name = trim($m[1]); + } + else if (preg_match('/^('.$email_rx.')$/', $val, $m)) { + $address = $m[1]; + $name = ''; + } + // special case (#1489092) + else if (preg_match('/(\s*)$/', $val, $m)) { + $address = 'MAILER-DAEMON'; + $name = substr($val, 0, -strlen($m[1])); + } + else if (preg_match('/('.$email_rx.')/', $val, $m)) { + $name = $m[1]; + } + else { + $name = $val; + } + + // unquote and/or decode name + if ($name) { + // An unquoted name ending with colon is a address group name, ignore it + if ($name[strlen($name)-1] == ':') { + $name = ''; + } + + if (strlen($name) > 1 && $name[0] == '"' && $name[strlen($name)-1] == '"') { + $name = substr($name, 1, -1); + $name = stripslashes($name); + } + + if ($decode) { + $name = self::decode_header($name, $fallback); + // some clients encode addressee name with quotes around it + if (strlen($name) > 1 && $name[0] == '"' && $name[strlen($name)-1] == '"') { + $name = substr($name, 1, -1); + } + } + } + + if (!$address && $name) { + $address = $name; + $name = ''; + } + + if ($address) { + $address = self::fix_email($address); + $result[$key] = ['name' => $name, 'address' => $address]; + } + } + + return $result; + } + + /** + * Explodes header (e.g. address-list) string into array of strings + * using specified separator characters with proper handling + * of quoted-strings and comments (RFC2822) + * + * @param string $separator String containing separator characters + * @param string $str Header string + * @param bool $remove_comments Enable to remove comments + * + * @return array Header items + */ + public static function explode_header_string($separator, $str, $remove_comments = false) + { + $length = strlen($str); + $result = []; + $quoted = false; + $comment = 0; + $out = ''; + + for ($i=0; $i<$length; $i++) { + // we're inside a quoted string + if ($quoted) { + if ($str[$i] == '"') { + $quoted = false; + } + else if ($str[$i] == "\\") { + if ($comment <= 0) { + $out .= "\\"; + } + $i++; + } + } + // we are inside a comment string + else if ($comment > 0) { + if ($str[$i] == ')') { + $comment--; + } + else if ($str[$i] == '(') { + $comment++; + } + else if ($str[$i] == "\\") { + $i++; + } + continue; + } + // separator, add to result array + else if (strpos($separator, $str[$i]) !== false) { + if ($out) { + $result[] = $out; + } + $out = ''; + continue; + } + // start of quoted string + else if ($str[$i] == '"') { + $quoted = true; + } + // start of comment + else if ($remove_comments && $str[$i] == '(') { + $comment++; + } + + if ($comment <= 0) { + $out .= $str[$i]; + } + } + + if ($out && $comment <= 0) { + $result[] = $out; + } + + return $result; + } + + /** + * Interpret a format=flowed message body according to RFC 2646 + * + * @param string $text Raw body formatted as flowed text + * @param string $mark Mark each flowed line with specified character + * @param bool $delsp Remove the trailing space of each flowed line + * + * @return string Interpreted text with unwrapped lines and stuffed space removed + */ + public static function unfold_flowed($text, $mark = null, $delsp = false) + { + $text = preg_split('/\r?\n/', $text); + $last = -1; + $q_level = 0; + $marks = []; + + foreach ($text as $idx => $line) { + if ($q = strspn($line, '>')) { + // remove quote chars + $line = substr($line, $q); + // remove (optional) space-staffing + if (isset($line[0]) && $line[0] === ' ') { + $line = substr($line, 1); + } + + // The same paragraph (We join current line with the previous one) when: + // - the same level of quoting + // - previous line was flowed + // - previous line contains more than only one single space (and quote char(s)) + if ($q == $q_level + && isset($text[$last]) && $text[$last][strlen($text[$last])-1] == ' ' + && !preg_match('/^>+ {0,1}$/', $text[$last]) + ) { + if ($delsp) { + $text[$last] = substr($text[$last], 0, -1); + } + $text[$last] .= $line; + unset($text[$idx]); + + if ($mark) { + $marks[$last] = true; + } + } + else { + $last = $idx; + } + } + else { + if ($line == '-- ') { + $last = $idx; + } + else { + // remove space-stuffing + if (isset($line[0]) && $line[0] === ' ') { + $line = substr($line, 1); + } + + $last_len = isset($text[$last]) ? strlen($text[$last]) : 0; + + if ( + $last_len && $line && !$q_level && $text[$last] != '-- ' + && isset($text[$last][$last_len-1]) && $text[$last][$last_len-1] == ' ' + ) { + if ($delsp) { + $text[$last] = substr($text[$last], 0, -1); + } + $text[$last] .= $line; + unset($text[$idx]); + + if ($mark) { + $marks[$last] = true; + } + } + else { + $text[$idx] = $line; + $last = $idx; + } + } + } + $q_level = $q; + } + + if (!empty($marks)) { + foreach (array_keys($marks) as $mk) { + $text[$mk] = $mark . $text[$mk]; + } + } + + return implode("\r\n", $text); + } + + /** + * Wrap the given text to comply with RFC 2646 + * + * @param string $text Text to wrap + * @param int $length Length + * @param string $charset Character encoding of $text + * + * @return string Wrapped text + */ + public static function format_flowed($text, $length = 72, $charset = null) + { + $text = preg_split('/\r?\n/', $text); + + foreach ($text as $idx => $line) { + if ($line != '-- ') { + if ($level = strspn($line, '>')) { + // remove quote chars + $line = substr($line, $level); + // remove (optional) space-staffing and spaces before the line end + $line = rtrim($line, ' '); + if (isset($line[0]) && $line[0] === ' ') { + $line = substr($line, 1); + } + + $prefix = str_repeat('>', $level) . ' '; + $line = $prefix . self::wordwrap($line, $length - $level - 2, " \r\n$prefix", false, $charset); + } + else if ($line) { + $line = self::wordwrap(rtrim($line), $length - 2, " \r\n", false, $charset); + // space-stuffing + $line = preg_replace('/(^|\r\n)(From| |>)/', '\\1 \\2', $line); + } + + $text[$idx] = $line; + } + } + + return implode("\r\n", $text); + } + + /** + * Improved wordwrap function with multibyte support. + * The code is based on Zend_Text_MultiByte::wordWrap(). + * + * @param string $string Text to wrap + * @param int $width Line width + * @param string $break Line separator + * @param bool $cut Enable to cut word + * @param string $charset Charset of $string + * @param bool $wrap_quoted When enabled quoted lines will not be wrapped + * + * @return string Text + */ + public static function wordwrap($string, $width = 75, $break = "\n", $cut = false, $charset = null, $wrap_quoted = true) + { + // Note: Never try to use iconv instead of mbstring functions here + // Iconv's substr/strlen are 100x slower (#1489113) + + if ($charset && $charset != RCUBE_CHARSET) { + $charset = rcube_charset::parse_charset($charset); + mb_internal_encoding($charset); + } + + // Convert \r\n to \n, this is our line-separator + $string = str_replace("\r\n", "\n", $string); + $separator = "\n"; // must be 1 character length + $result = []; + + while (($stringLength = mb_strlen($string)) > 0) { + $breakPos = mb_strpos($string, $separator, 0); + + // quoted line (do not wrap) + if ($wrap_quoted && $string[0] == '>') { + if ($breakPos === $stringLength - 1 || $breakPos === false) { + $subString = $string; + $cutLength = null; + } + else { + $subString = mb_substr($string, 0, $breakPos); + $cutLength = $breakPos + 1; + } + } + // next line found and current line is shorter than the limit + else if ($breakPos !== false && $breakPos < $width) { + if ($breakPos === $stringLength - 1) { + $subString = $string; + $cutLength = null; + } + else { + $subString = mb_substr($string, 0, $breakPos); + $cutLength = $breakPos + 1; + } + } + else { + $subString = mb_substr($string, 0, $width); + + // last line + if ($breakPos === false && $subString === $string) { + $cutLength = null; + } + else { + $nextChar = mb_substr($string, $width, 1); + + if ($nextChar === ' ' || $nextChar === $separator) { + $afterNextChar = mb_substr($string, $width + 1, 1); + + // Note: mb_substr() does never return False + if ($afterNextChar === false || $afterNextChar === '') { + $subString .= $nextChar; + } + + $cutLength = mb_strlen($subString) + 1; + } + else { + $spacePos = mb_strrpos($subString, ' ', 0); + + if ($spacePos !== false) { + $subString = mb_substr($subString, 0, $spacePos); + $cutLength = $spacePos + 1; + } + else if ($cut === false) { + $spacePos = mb_strpos($string, ' ', 0); + + if ($spacePos !== false && ($breakPos === false || $spacePos < $breakPos)) { + $subString = mb_substr($string, 0, $spacePos); + $cutLength = $spacePos + 1; + } + else if ($breakPos === false) { + $subString = $string; + $cutLength = null; + } + else { + $subString = mb_substr($string, 0, $breakPos); + $cutLength = $breakPos + 1; + } + } + else { + $cutLength = $width; + } + } + } + } + + $result[] = $subString; + + if ($cutLength !== null) { + $string = mb_substr($string, $cutLength, ($stringLength - $cutLength)); + } + else { + break; + } + } + + if ($charset && $charset != RCUBE_CHARSET) { + mb_internal_encoding(RCUBE_CHARSET); + } + + return implode($break, $result); + } + + /** + * A method to guess the mime_type of an attachment. + * + * @param string $path Path to the file or file contents + * @param string $name File name (with suffix) + * @param string $failover Mime type supplied for failover + * @param bool $is_stream Set to True if $path contains file contents + * @param bool $skip_suffix Set to True if the config/mimetypes.php map should be ignored + * + * @return string + * @author Till Klampaeckel + * @see http://de2.php.net/manual/en/ref.fileinfo.php + * @see http://de2.php.net/mime_content_type + */ + public static function file_content_type($path, $name, $failover = 'application/octet-stream', $is_stream = false, $skip_suffix = false) + { + $mime_type = null; + $config = rcube::get_instance()->config; + + // Detect mimetype using filename extension + if (!$skip_suffix) { + $mime_type = self::file_ext_type($name); + } + + // try fileinfo extension if available + if (!$mime_type && function_exists('finfo_open')) { + $mime_magic = $config->get('mime_magic'); + // null as a 2nd argument should be the same as no argument + // this however is not true on all systems/versions + if ($mime_magic) { + $finfo = finfo_open(FILEINFO_MIME, $mime_magic); + } + else { + $finfo = finfo_open(FILEINFO_MIME); + } + + if ($finfo) { + $func = $is_stream ? 'finfo_buffer' : 'finfo_file'; + $mime_type = $func($finfo, $path, FILEINFO_MIME_TYPE); + finfo_close($finfo); + } + } + + // try PHP's mime_content_type + if (!$mime_type && !$is_stream && function_exists('mime_content_type')) { + $mime_type = @mime_content_type($path); + } + + // fall back to user-submitted string + if (!$mime_type) { + $mime_type = $failover; + } + + return $mime_type; + } + + /** + * File type detection based on file name only. + * + * @param string $filename Path to the file or file contents + * + * @return string|null Mimetype label + */ + public static function file_ext_type($filename) + { + static $mime_ext = []; + + if (empty($mime_ext)) { + foreach (rcube::get_instance()->config->resolve_paths('mimetypes.php') as $fpath) { + $mime_ext = array_merge($mime_ext, (array) @include($fpath)); + } + } + + // use file name suffix with hard-coded mime-type map + if (!empty($mime_ext) && $filename) { + $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); + if ($ext && !empty($mime_ext[$ext])) { + return $mime_ext[$ext]; + } + } + } + + /** + * Get mimetype => file extension mapping + * + * @param string $mimetype Mime-Type to get extensions for + * + * @return array List of extensions matching the given mimetype or a hash array + * with ext -> mimetype mappings if $mimetype is not given + */ + public static function get_mime_extensions($mimetype = null) + { + static $mime_types, $mime_extensions; + + // return cached data + if (is_array($mime_types)) { + return $mimetype ? (isset($mime_types[$mimetype]) ? $mime_types[$mimetype] : []) : $mime_extensions; + } + + // load mapping file + $file_paths = []; + + if ($mime_types = rcube::get_instance()->config->get('mime_types')) { + $file_paths[] = $mime_types; + } + + // try common locations + if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { + $file_paths[] = 'C:/xampp/apache/conf/mime.types'; + } + else { + $file_paths[] = '/etc/mime.types'; + $file_paths[] = '/etc/httpd/mime.types'; + $file_paths[] = '/etc/httpd2/mime.types'; + $file_paths[] = '/etc/apache/mime.types'; + $file_paths[] = '/etc/apache2/mime.types'; + $file_paths[] = '/etc/nginx/mime.types'; + $file_paths[] = '/usr/local/etc/httpd/conf/mime.types'; + $file_paths[] = '/usr/local/etc/apache/conf/mime.types'; + $file_paths[] = '/usr/local/etc/apache24/mime.types'; + } + + $mime_types = []; + $mime_extensions = []; + $lines = []; + $regex = "/([\w\+\-\.\/]+)\s+([\w\s]+)/i"; + + foreach ($file_paths as $fp) { + if (@is_readable($fp)) { + $lines = file($fp, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + break; + } + } + + foreach ($lines as $line) { + // skip comments or mime types w/o any extensions + if ($line[0] == '#' || !preg_match($regex, $line, $matches)) { + continue; + } + + $mime = $matches[1]; + + foreach (explode(' ', $matches[2]) as $ext) { + $ext = trim($ext); + $mime_types[$mime][] = $ext; + $mime_extensions[$ext] = $mime; + } + } + + // fallback to some well-known types most important for daily emails + if (empty($mime_types)) { + foreach (rcube::get_instance()->config->resolve_paths('mimetypes.php') as $fpath) { + $mime_extensions = array_merge($mime_extensions, (array) @include($fpath)); + } + + foreach ($mime_extensions as $ext => $mime) { + $mime_types[$mime][] = $ext; + } + } + + // Add some known aliases that aren't included by some mime.types (#1488891) + // the order is important here so standard extensions have higher prio + $aliases = [ + 'image/gif' => ['gif'], + 'image/png' => ['png'], + 'image/x-png' => ['png'], + 'image/jpeg' => ['jpg', 'jpeg', 'jpe'], + 'image/jpg' => ['jpg', 'jpeg', 'jpe'], + 'image/pjpeg' => ['jpg', 'jpeg', 'jpe'], + 'image/tiff' => ['tif'], + 'image/bmp' => ['bmp'], + 'image/x-ms-bmp' => ['bmp'], + 'message/rfc822' => ['eml'], + 'text/x-mail' => ['eml'], + ]; + + foreach ($aliases as $mime => $exts) { + if (isset($mime_types[$mime])) { + $mime_types[$mime] = array_unique(array_merge((array) $mime_types[$mime], $exts)); + } + else { + $mime_types[$mime] = $exts; + } + + foreach ($exts as $ext) { + if (!isset($mime_extensions[$ext])) { + $mime_extensions[$ext] = $mime; + } + } + } + + if ($mimetype) { + return !empty($mime_types[$mimetype]) ? $mime_types[$mimetype] : []; + } + + return $mime_extensions; + } + + /** + * Detect image type of the given binary data by checking magic numbers. + * + * @param string $data Binary file content + * + * @return string Detected mime-type or jpeg as fallback + */ + public static function image_content_type($data) + { + $type = 'jpeg'; + if (preg_match('/^\x89\x50\x4E\x47/', $data)) $type = 'png'; + else if (preg_match('/^\x47\x49\x46\x38/', $data)) $type = 'gif'; + else if (preg_match('/^\x00\x00\x01\x00/', $data)) $type = 'ico'; + // else if (preg_match('/^\xFF\xD8\xFF\xE0/', $data)) $type = 'jpeg'; + + return 'image/' . $type; + } + + /** + * Try to fix invalid email addresses + */ + public static function fix_email($email) + { + $parts = rcube_utils::explode_quoted_string('@', $email); + + foreach ($parts as $idx => $part) { + // remove redundant quoting (#1490040) + if (isset($part[0]) && $part[0] == '"' && preg_match('/^"([a-zA-Z0-9._+=-]+)"$/', $part, $m)) { + $parts[$idx] = $m[1]; + } + } + + return implode('@', $parts); + } + + /** + * Fix mimetype name. + * + * @param string $type Mimetype + * + * @return string Mimetype + */ + public static function fix_mimetype($type) + { + $type = strtolower(trim($type)); + $aliases = [ + 'image/x-ms-bmp' => 'image/bmp', // #4771 + 'pdf' => 'application/pdf', // #6816 + ]; + + if (!empty($aliases[$type])) { + return $aliases[$type]; + } + + // Some versions of Outlook create garbage Content-Type: + // application/pdf.A520491B_3BF7_494D_8855_7FAC2C6C0608 + if (preg_match('/^application\/pdf.+/', $type)) { + return 'application/pdf'; + } + + // treat image/pjpeg (image/pjpg, image/jpg) as image/jpeg (#4196) + if (preg_match('/^image\/p?jpe?g$/', $type)) { + return 'image/jpeg'; + } + + return $type; + } +} diff --git a/admin/tool/messageinbound/roundcube/rcube_result_index.php b/admin/tool/messageinbound/roundcube/rcube_result_index.php new file mode 100644 index 00000000000..8ef164e0129 --- /dev/null +++ b/admin/tool/messageinbound/roundcube/rcube_result_index.php @@ -0,0 +1,446 @@ + | + | Author: Aleksander Machniak | + +-----------------------------------------------------------------------+ +*/ + +/** + * Class for accessing IMAP's SORT/SEARCH/ESEARCH result + * + * @package Framework + * @subpackage Storage + */ +class rcube_result_index +{ + public $incomplete = false; + + protected $raw_data; + protected $mailbox; + protected $meta = []; + protected $params = []; + protected $order = 'ASC'; + + const SEPARATOR_ELEMENT = ' '; + + + /** + * Object constructor. + */ + public function __construct($mailbox = null, $data = null, $order = null) + { + $this->mailbox = $mailbox; + $this->order = $order == 'DESC' ? 'DESC' : 'ASC'; + $this->init($data); + } + + /** + * Initializes object with SORT command response + * + * @param string $data IMAP response string + */ + public function init($data = null) + { + $this->meta = []; + + $data = explode('*', (string)$data); + + // ...skip unilateral untagged server responses + for ($i=0, $len=count($data); $i<$len; $i++) { + $data_item = &$data[$i]; + if (preg_match('/^ SORT/i', $data_item)) { + // valid response, initialize raw_data for is_error() + $this->raw_data = ''; + $data_item = substr($data_item, 5); + break; + } + else if (preg_match('/^ (E?SEARCH)/i', $data_item, $m)) { + // valid response, initialize raw_data for is_error() + $this->raw_data = ''; + $data_item = substr($data_item, strlen($m[0])); + + if (strtoupper($m[1]) == 'ESEARCH') { + $data_item = trim($data_item); + // remove MODSEQ response + if (preg_match('/\(MODSEQ ([0-9]+)\)$/i', $data_item, $m)) { + $data_item = substr($data_item, 0, -strlen($m[0])); + $this->params['MODSEQ'] = $m[1]; + } + // remove TAG response part + if (preg_match('/^\(TAG ["a-z0-9]+\)\s*/i', $data_item, $m)) { + $data_item = substr($data_item, strlen($m[0])); + } + // remove UID + $data_item = preg_replace('/^UID\s*/i', '', $data_item); + + // ESEARCH parameters + while (preg_match('/^([a-z]+) ([0-9:,]+)\s*/i', $data_item, $m)) { + $param = strtoupper($m[1]); + $value = $m[2]; + + $this->params[$param] = $value; + $data_item = substr($data_item, strlen($m[0])); + + if (in_array($param, ['COUNT', 'MIN', 'MAX'])) { + $this->meta[strtolower($param)] = (int) $value; + } + } + +// @TODO: Implement compression using compressMessageSet() in __sleep() and __wakeup() ? +// @TODO: work with compressed result?! + if (isset($this->params['ALL'])) { + $data_item = implode(self::SEPARATOR_ELEMENT, + rcube_imap_generic::uncompressMessageSet($this->params['ALL'])); + } + } + + break; + } + + unset($data[$i]); + } + + $data = array_filter($data); + + if (empty($data)) { + return; + } + + $data = array_shift($data); + $data = trim($data); + $data = preg_replace('/[\r\n]/', '', $data); + $data = preg_replace('/\s+/', ' ', $data); + + $this->raw_data = $data; + } + + /** + * Checks the result from IMAP command + * + * @return bool True if the result is an error, False otherwise + */ + public function is_error() + { + return $this->raw_data === null; + } + + /** + * Checks if the result is empty + * + * @return bool True if the result is empty, False otherwise + */ + public function is_empty() + { + return empty($this->raw_data) + && empty($this->meta['max']) && empty($this->meta['min']) && empty($this->meta['count']); + } + + /** + * Returns number of elements in the result + * + * @return int Number of elements + */ + public function count() + { + if (isset($this->meta['count'])) { + return $this->meta['count']; + } + + if (empty($this->raw_data)) { + $this->meta['count'] = 0; + $this->meta['length'] = 0; + } + else { + $this->meta['count'] = 1 + substr_count($this->raw_data, self::SEPARATOR_ELEMENT); + } + + return $this->meta['count']; + } + + /** + * Returns number of elements in the result. + * Alias for count() for compatibility with rcube_result_thread + * + * @return int Number of elements + */ + public function count_messages() + { + return $this->count(); + } + + /** + * Returns maximal message identifier in the result + * + * @return int|null Maximal message identifier + */ + public function max() + { + if ($this->is_empty()) { + return null; + } + + if (!isset($this->meta['max'])) { + $this->meta['max'] = null; + $all = $this->get(); + if (!empty($all)) { + $this->meta['max'] = (int) max($all); + } + } + + return $this->meta['max']; + } + + /** + * Returns minimal message identifier in the result + * + * @return int|null Minimal message identifier + */ + public function min() + { + if ($this->is_empty()) { + return null; + } + + if (!isset($this->meta['min'])) { + $this->meta['min'] = null; + $all = $this->get(); + if (!empty($all)) { + $this->meta['min'] = (int) min($all); + } + } + + return $this->meta['min']; + } + + /** + * Slices data set. + * + * @param int $offset Offset (as for PHP's array_slice()) + * @param int $length Number of elements (as for PHP's array_slice()) + */ + public function slice($offset, $length) + { + $data = $this->get(); + $data = array_slice($data, $offset, $length); + + $this->meta = []; + $this->meta['count'] = count($data); + $this->raw_data = implode(self::SEPARATOR_ELEMENT, $data); + } + + /** + * Filters data set. Removes elements not listed in $ids list. + * + * @param array $ids List of IDs to remove. + */ + public function filter($ids = []) + { + $data = $this->get(); + $data = array_intersect($data, $ids); + + $this->meta = []; + $this->meta['count'] = count($data); + $this->raw_data = implode(self::SEPARATOR_ELEMENT, $data); + } + + /** + * Reverts order of elements in the result + */ + public function revert() + { + $this->order = $this->order == 'ASC' ? 'DESC' : 'ASC'; + + if (empty($this->raw_data)) { + return; + } + + $data = $this->get(); + $data = array_reverse($data); + $this->raw_data = implode(self::SEPARATOR_ELEMENT, $data); + + $this->meta['pos'] = []; + } + + /** + * Check if the given message ID exists in the object + * + * @param int $msgid Message ID + * @param bool $get_index When enabled element's index will be returned. + * Elements are indexed starting with 0 + * + * @return mixed False if message ID doesn't exist, True if exists or + * index of the element if $get_index=true + */ + public function exists($msgid, $get_index = false) + { + if (empty($this->raw_data)) { + return false; + } + + $msgid = (int) $msgid; + $begin = implode('|', ['^', preg_quote(self::SEPARATOR_ELEMENT, '/')]); + $end = implode('|', ['$', preg_quote(self::SEPARATOR_ELEMENT, '/')]); + + if (preg_match("/($begin)$msgid($end)/", $this->raw_data, $m, + $get_index ? PREG_OFFSET_CAPTURE : 0) + ) { + if ($get_index) { + $idx = 0; + if (!empty($m[0][1])) { + $idx = 1 + substr_count($this->raw_data, self::SEPARATOR_ELEMENT, 0, $m[0][1]); + } + // cache position of this element, so we can use it in get_element() + $this->meta['pos'][$idx] = (int)$m[0][1]; + + return $idx; + } + + return true; + } + + return false; + } + + /** + * Return all messages in the result. + * + * @return array List of message IDs + */ + public function get() + { + if (empty($this->raw_data)) { + return []; + } + + return explode(self::SEPARATOR_ELEMENT, $this->raw_data); + } + + /** + * Return all messages in the result. + * + * @return array List of message IDs + */ + public function get_compressed() + { + if (empty($this->raw_data)) { + return ''; + } + + return rcube_imap_generic::compressMessageSet($this->get()); + } + + /** + * Return result element at specified index + * + * @param int|string $index Element's index or "FIRST" or "LAST" + * + * @return int|null Element value + */ + public function get_element($index) + { + if (empty($this->raw_data)) { + return null; + } + + $count = $this->count(); + + // first element + if ($index === 0 || $index === '0' || $index === 'FIRST') { + $pos = strpos($this->raw_data, self::SEPARATOR_ELEMENT); + if ($pos === false) { + $result = (int) $this->raw_data; + } + else { + $result = (int) substr($this->raw_data, 0, $pos); + } + + return $result; + } + + // last element + if ($index === 'LAST' || $index == $count-1) { + $pos = strrpos($this->raw_data, self::SEPARATOR_ELEMENT); + if ($pos === false) { + $result = (int) $this->raw_data; + } + else { + $result = (int) substr($this->raw_data, $pos); + } + + return $result; + } + + // do we know the position of the element or the neighbour of it? + if (!empty($this->meta['pos'])) { + if (isset($this->meta['pos'][$index])) { + $pos = $this->meta['pos'][$index]; + } + else if (isset($this->meta['pos'][$index-1])) { + $pos = strpos($this->raw_data, self::SEPARATOR_ELEMENT, + $this->meta['pos'][$index-1] + 1); + } + else if (isset($this->meta['pos'][$index+1])) { + $pos = strrpos($this->raw_data, self::SEPARATOR_ELEMENT, + $this->meta['pos'][$index+1] - $this->length() - 1); + } + + if (isset($pos) && preg_match('/([0-9]+)/', $this->raw_data, $m, 0, $pos)) { + return (int) $m[1]; + } + } + + // Finally use less effective method + $data = explode(self::SEPARATOR_ELEMENT, $this->raw_data); + + return (int) $data[$index]; + } + + /** + * Returns response parameters, e.g. ESEARCH's MIN/MAX/COUNT/ALL/MODSEQ + * or internal data e.g. MAILBOX, ORDER + * + * @param ?string $param Parameter name + * + * @return array|string Response parameters or parameter value + */ + public function get_parameters($param = null) + { + $params = $this->params; + $params['MAILBOX'] = $this->mailbox; + $params['ORDER'] = $this->order; + + if ($param !== null) { + return $params[$param] ?? null; + } + + return $params; + } + + /** + * Returns length of internal data representation + * + * @return int Data length + */ + protected function length() + { + if (!isset($this->meta['length'])) { + $this->meta['length'] = strlen($this->raw_data); + } + + return $this->meta['length']; + } +} diff --git a/admin/tool/messageinbound/roundcube/rcube_result_thread.php b/admin/tool/messageinbound/roundcube/rcube_result_thread.php new file mode 100644 index 00000000000..df759d1bfbf --- /dev/null +++ b/admin/tool/messageinbound/roundcube/rcube_result_thread.php @@ -0,0 +1,699 @@ + | + | Author: Aleksander Machniak | + +-----------------------------------------------------------------------+ +*/ + +/** + * Class for accessing IMAP's THREAD result + * + * @package Framework + * @subpackage Storage + */ +class rcube_result_thread +{ + public $incomplete = false; + + protected $raw_data; + protected $mailbox; + protected $meta = []; + protected $order = 'ASC'; + + const SEPARATOR_ELEMENT = ' '; + const SEPARATOR_ITEM = '~'; + const SEPARATOR_LEVEL = ':'; + + + /** + * Object constructor. + */ + public function __construct($mailbox = null, $data = null) + { + $this->mailbox = $mailbox; + $this->init($data); + } + + /** + * Initializes object with IMAP command response + * + * @param string $data IMAP response string + */ + public function init($data = null) + { + $this->meta = []; + + $data = explode('*', (string) $data); + + // ...skip unilateral untagged server responses + for ($i = 0, $len = count($data); $i < $len; $i++) { + if (preg_match('/^ THREAD/i', $data[$i])) { + // valid response, initialize raw_data for is_error() + $this->raw_data = ''; + $data[$i] = substr($data[$i], 7); + break; + } + + unset($data[$i]); + } + + if (empty($data)) { + return; + } + + $data = array_shift($data); + $data = trim($data); + $data = preg_replace('/[\r\n]/', '', $data); + $data = preg_replace('/\s+/', ' ', $data); + + $this->raw_data = empty($data) ? '' : $this->parse_thread($data); + } + + /** + * Checks the result from IMAP command + * + * @return bool True if the result is an error, False otherwise + */ + public function is_error() + { + return $this->raw_data === null; + } + + /** + * Checks if the result is empty + * + * @return bool True if the result is empty, False otherwise + */ + public function is_empty() + { + return empty($this->raw_data); + } + + /** + * Returns number of elements (threads) in the result + * + * @return int Number of elements + */ + public function count() + { + if (isset($this->meta['count'])) { + return $this->meta['count']; + } + + if (empty($this->raw_data)) { + $this->meta['count'] = 0; + } + else { + $this->meta['count'] = 1 + substr_count($this->raw_data, self::SEPARATOR_ELEMENT); + } + + if (!$this->meta['count']) { + $this->meta['messages'] = 0; + } + + return $this->meta['count']; + } + + /** + * Returns number of all messages in the result + * + * @return int Number of elements + */ + public function count_messages() + { + if (isset($this->meta['messages'])) { + return $this->meta['messages']; + } + + if (empty($this->raw_data)) { + $this->meta['messages'] = 0; + } + else { + $this->meta['messages'] = 1 + + substr_count($this->raw_data, self::SEPARATOR_ELEMENT) + + substr_count($this->raw_data, self::SEPARATOR_ITEM); + } + + if ($this->meta['messages'] == 0 || $this->meta['messages'] == 1) { + $this->meta['count'] = $this->meta['messages']; + } + + return $this->meta['messages']; + } + + /** + * Returns maximum message identifier in the result + * + * @return int|null Maximum message identifier + */ + public function max() + { + if ($this->is_empty()) { + return null; + } + + if (!isset($this->meta['max'])) { + $this->meta['max'] = (int) @max($this->get()); + } + + return $this->meta['max']; + } + + /** + * Returns minimum message identifier in the result + * + * @return int|null Minimum message identifier + */ + public function min() + { + if ($this->is_empty()) { + return null; + } + + if (!isset($this->meta['min'])) { + $this->meta['min'] = (int) @min($this->get()); + } + + return $this->meta['min']; + } + + /** + * Slices data set. + * + * @param int $offset Offset (as for PHP's array_slice()) + * @param int $length Number of elements (as for PHP's array_slice()) + */ + public function slice($offset, $length) + { + $data = explode(self::SEPARATOR_ELEMENT, $this->raw_data); + $data = array_slice($data, $offset, $length); + + $this->meta = []; + $this->meta['count'] = count($data); + $this->raw_data = implode(self::SEPARATOR_ELEMENT, $data); + } + + /** + * Filters data set. Removes threads not listed in $roots list. + * + * @param array $roots List of IDs of thread roots. + */ + public function filter($roots) + { + $datalen = strlen($this->raw_data); + $roots = array_flip($roots); + $result = ''; + $start = 0; + + $this->meta = ['count' => 0]; + + while ($start < $datalen + && (($pos = strpos($this->raw_data, self::SEPARATOR_ELEMENT, $start)) !== false + || ($pos = $datalen)) + ) { + $len = $pos - $start; + $elem = substr($this->raw_data, $start, $len); + $start = $pos + 1; + + // extract root message ID + if ($npos = strpos($elem, self::SEPARATOR_ITEM)) { + $root = (int) substr($elem, 0, $npos); + } + else { + $root = $elem; + } + + if (isset($roots[$root])) { + $this->meta['count']++; + $result .= self::SEPARATOR_ELEMENT . $elem; + } + } + + $this->raw_data = ltrim($result, self::SEPARATOR_ELEMENT); + } + + /** + * Reverts order of elements in the result + */ + public function revert() + { + $this->order = $this->order == 'ASC' ? 'DESC' : 'ASC'; + + if (empty($this->raw_data)) { + return; + } + + $data = explode(self::SEPARATOR_ELEMENT, $this->raw_data); + $data = array_reverse($data); + $this->raw_data = implode(self::SEPARATOR_ELEMENT, $data); + + $this->meta['pos'] = []; + } + + /** + * Check if the given message ID exists in the object + * + * @param int $msgid Message ID + * @param bool $get_index When enabled element's index will be returned. + * Elements are indexed starting with 0 + * + * @return bool True on success, False if message ID doesn't exist + */ + public function exists($msgid, $get_index = false) + { + $msgid = (int) $msgid; + $begin = implode('|', [ + '^', + preg_quote(self::SEPARATOR_ELEMENT, '/'), + preg_quote(self::SEPARATOR_LEVEL, '/'), + ]); + $end = implode('|', [ + '$', + preg_quote(self::SEPARATOR_ELEMENT, '/'), + preg_quote(self::SEPARATOR_ITEM, '/'), + ]); + + if (preg_match("/($begin)$msgid($end)/", $this->raw_data, $m, + $get_index ? PREG_OFFSET_CAPTURE : 0) + ) { + if ($get_index) { + $idx = 0; + if ($m[0][1]) { + $idx = substr_count($this->raw_data, self::SEPARATOR_ELEMENT, 0, $m[0][1]+1) + + substr_count($this->raw_data, self::SEPARATOR_ITEM, 0, $m[0][1]+1); + } + // cache position of this element, so we can use it in get_element() + $this->meta['pos'][$idx] = (int)$m[0][1]; + + return $idx; + } + return true; + } + + return false; + } + + /** + * Return IDs of all messages in the result. Threaded data will be flattened. + * + * @return array List of message identifiers + */ + public function get() + { + if (empty($this->raw_data)) { + return []; + } + + $regexp = '/(' . preg_quote(self::SEPARATOR_ELEMENT, '/') + . '|' . preg_quote(self::SEPARATOR_ITEM, '/') . '[0-9]+' . preg_quote(self::SEPARATOR_LEVEL, '/') + .')/'; + + return preg_split($regexp, $this->raw_data); + } + + /** + * Return all messages in the result. + * + * @return array List of message identifiers + */ + public function get_compressed() + { + if (empty($this->raw_data)) { + return ''; + } + + return rcube_imap_generic::compressMessageSet($this->get()); + } + + /** + * Return result element at specified index (all messages, not roots) + * + * @param int|string $index Element's index or "FIRST" or "LAST" + * + * @return int Element value + */ + public function get_element($index) + { + $count = $this->count(); + + if (!$count) { + return null; + } + + // first element + if ($index === 0 || $index === '0' || $index === 'FIRST') { + preg_match('/^([0-9]+)/', $this->raw_data, $m); + $result = (int) $m[1]; + return $result; + } + + // last element + if ($index === 'LAST' || $index == $count-1) { + preg_match('/([0-9]+)$/', $this->raw_data, $m); + $result = (int) $m[1]; + return $result; + } + + // do we know the position of the element or the neighbour of it? + if (!empty($this->meta['pos'])) { + $element = preg_quote(self::SEPARATOR_ELEMENT, '/'); + $item = preg_quote(self::SEPARATOR_ITEM, '/') . '[0-9]+' . preg_quote(self::SEPARATOR_LEVEL, '/') .'?'; + $regexp = '(' . $element . '|' . $item . ')'; + + if (isset($this->meta['pos'][$index])) { + if (preg_match('/([0-9]+)/', $this->raw_data, $m, null, $this->meta['pos'][$index])) { + $result = $m[1]; + } + } + else if (isset($this->meta['pos'][$index-1])) { + // get chunk of data after previous element + $data = substr($this->raw_data, $this->meta['pos'][$index-1]+1, 50); + $data = preg_replace('/^[0-9]+/', '', $data); // remove UID at $index position + $data = preg_replace("/^$regexp/", '', $data); // remove separator + if (preg_match('/^([0-9]+)/', $data, $m)) { + $result = $m[1]; + } + } + else if (isset($this->meta['pos'][$index+1])) { + // get chunk of data before next element + $pos = max(0, $this->meta['pos'][$index+1] - 50); + $len = min(50, $this->meta['pos'][$index+1]); + $data = substr($this->raw_data, $pos, $len); + $data = preg_replace("/$regexp\$/", '', $data); // remove separator + + if (preg_match('/([0-9]+)$/', $data, $m)) { + $result = $m[1]; + } + } + + if (isset($result)) { + return (int) $result; + } + } + + // Finally use less effective method + $data = $this->get(); + + return $data[$index] ?? null; + } + + /** + * Returns response parameters e.g. MAILBOX, ORDER + * + * @param string $param Parameter name + * + * @return array|string Response parameters or parameter value + */ + public function get_parameters($param=null) + { + $params = [ + 'MAILBOX' => $this->mailbox, + 'ORDER' => $this->order, + ]; + + if ($param !== null) { + return $params[$param]; + } + + return $params; + } + + /** + * THREAD=REFS sorting implementation (based on provided index) + * + * @param rcube_result_index $index Sorted message identifiers + */ + public function sort($index) + { + $this->order = $index->get_parameters('ORDER'); + + if (empty($this->raw_data)) { + return; + } + + // when sorting search result it's good to make the index smaller + if ($index->count() != $this->count_messages()) { + $index->filter($this->get()); + } + + $result = array_fill_keys($index->get(), null); + $datalen = strlen($this->raw_data); + $start = 0; + + // Here we're parsing raw_data twice, we want only one big array + // in memory at a time + + // Assign roots + while ( + ($start < $datalen && ($pos = strpos($this->raw_data, self::SEPARATOR_ELEMENT, $start))) + || ($start < $datalen && ($pos = $datalen)) + ) { + $len = $pos - $start; + $elem = substr($this->raw_data, $start, $len); + $start = $pos + 1; + + $items = explode(self::SEPARATOR_ITEM, $elem); + $root = (int) array_shift($items); + + if ($root) { + $result[$root] = $root; + foreach ($items as $item) { + list($lv, $id) = explode(self::SEPARATOR_LEVEL, $item); + $result[$id] = $root; + } + } + } + + // get only unique roots + $result = array_filter($result); // make sure there are no nulls + $result = array_unique($result); + + // Re-sort raw data + $result = array_fill_keys($result, null); + $start = 0; + + while ( + ($start < $datalen && ($pos = strpos($this->raw_data, self::SEPARATOR_ELEMENT, $start))) + || ($start < $datalen && ($pos = $datalen)) + ) { + $len = $pos - $start; + $elem = substr($this->raw_data, $start, $len); + $start = $pos + 1; + + $npos = strpos($elem, self::SEPARATOR_ITEM); + $root = (int) ($npos ? substr($elem, 0, $npos) : $elem); + + $result[$root] = $elem; + } + + $this->raw_data = implode(self::SEPARATOR_ELEMENT, $result); + } + + /** + * Returns data as tree + * + * @return array Data tree + */ + public function get_tree() + { + $datalen = strlen($this->raw_data); + $result = []; + $start = 0; + + while ($start < $datalen + && (($pos = strpos($this->raw_data, self::SEPARATOR_ELEMENT, $start)) !== false + || ($pos = $datalen)) + ) { + $len = $pos - $start; + $elem = substr($this->raw_data, $start, $len); + $items = explode(self::SEPARATOR_ITEM, $elem); + $result[array_shift($items)] = $this->build_thread($items); + $start = $pos + 1; + } + + return $result; + } + + /** + * Returns thread depth and children data + * + * @return array Thread data + */ + public function get_thread_data() + { + $data = $this->get_tree(); + $depth = []; + $children = []; + + $this->build_thread_data($data, $depth, $children); + + return [$depth, $children]; + } + + /** + * Creates 'depth' and 'children' arrays from stored thread 'tree' data. + */ + protected function build_thread_data($data, &$depth, &$children, $level = 0) + { + foreach ((array)$data as $key => $val) { + $empty = empty($val) || !is_array($val); + $children[$key] = !$empty; + $depth[$key] = $level; + if (!$empty) { + $this->build_thread_data($val, $depth, $children, $level + 1); + } + } + } + + /** + * Converts part of the raw thread into an array + */ + protected function build_thread($items, $level = 1, &$pos = 0) + { + $result = []; + + for ($len=count($items); $pos < $len; $pos++) { + list($lv, $id) = explode(self::SEPARATOR_LEVEL, $items[$pos]); + if ($level == $lv) { + $pos++; + $result[$id] = $this->build_thread($items, $level+1, $pos); + } + else { + $pos--; + break; + } + } + + return $result; + } + + /** + * IMAP THREAD response parser + */ + protected function parse_thread($str, $begin = 0, $end = 0, $depth = 0) + { + // Don't be tempted to change $str to pass by reference to speed this up - it will slow it down by about + // 7 times instead :-) See comments on http://uk2.php.net/references and this article: + // http://derickrethans.nl/files/phparch-php-variables-article.pdf + $node = ''; + if (!$end) { + $end = strlen($str); + } + + // Let's try to store data in max. compacted structure as a string, + // arrays handling is much more expensive + // For the following structure: THREAD (2)(3 6 (4 23)(44 7 96))((11)(12)) + // -- 2 + // -- 3 + // \-- 6 + // |-- 4 + // | \-- 23 + // | + // \-- 44 + // \-- 7 + // \-- 96 + // -- 11 + // \-- 12 + // + // The output will be: 2 3~1:6~2:4~3:23~2:44~3:7~4:96 11~1:12 + // Note: The "11" thread has no root, we use the first message as root + + if ($str[$begin] != '(') { + // find next bracket + $stop = $begin + strcspn($str, '()', $begin, $end - $begin); + $messages = explode(' ', trim(substr($str, $begin, $stop - $begin))); + + if (empty($messages)) { + return $node; + } + + foreach ($messages as $msg) { + if ($msg) { + $node .= ($depth ? self::SEPARATOR_ITEM.$depth.self::SEPARATOR_LEVEL : '').$msg; + if (isset($this->meta['messages'])) { + $this->meta['messages']++; + } + else { + $this->meta['messages'] = 1; + } + $depth++; + } + } + + if ($stop < $end) { + $node .= $this->parse_thread($str, $stop, $end, $depth); + } + } + else { + $off = $begin; + while ($off < $end) { + $start = $off; + $off++; + $n = 1; + while ($n > 0) { + $p = strpos($str, ')', $off); + if ($p === false) { + // error, wrong structure, mismatched brackets in IMAP THREAD response + // @TODO: write error to the log or maybe set $this->raw_data = null; + return $node; + } + + $p1 = strpos($str, '(', $off); + if ($p1 !== false && $p1 < $p) { + $off = $p1 + 1; + $n++; + } + else { + $off = $p + 1; + $n--; + } + } + + // Handle threads with missing parent by using first message as root + if (substr_compare($str, '((', $start, 2) === 0) { + // Extract the current thread, e.g. "((1)(2))" + $thread = substr($str, $start, $off - $start); + // Length of the first token, e.g. "(1)" + $len = strspn($thread, '(0123456789', 1) + 1; + // Extract the token and modify it to look like a thread root + $token = substr($thread, 1, $len); + // Warning: The order is important + $token = str_replace('(', '', $token); + $token = str_replace(' ', ' (', $token); + $token = str_replace(')', ' ', $token); + $thread = substr_replace($thread, $token, 1, $len); + // Parse the thread + $thread = $this->parse_thread($thread, 0, 0, $depth); + } + else { + $thread = $this->parse_thread($str, $start + 1, $off - 1, $depth); + } + + if ($thread) { + if (!$depth) { + if ($node) { + $node .= self::SEPARATOR_ELEMENT; + } + } + $node .= $thread; + } + } + } + + return $node; + } +} diff --git a/admin/tool/messageinbound/roundcube/rcube_utils.php b/admin/tool/messageinbound/roundcube/rcube_utils.php new file mode 100644 index 00000000000..ba058eee3b0 --- /dev/null +++ b/admin/tool/messageinbound/roundcube/rcube_utils.php @@ -0,0 +1,1687 @@ + | + | Author: Aleksander Machniak | + +-----------------------------------------------------------------------+ +*/ + +/** + * Utility class providing common functions + * + * @package Framework + * @subpackage Utils + */ +class rcube_utils +{ + // define constants for input reading + const INPUT_GET = 1; + const INPUT_POST = 2; + const INPUT_COOKIE = 4; + const INPUT_GP = 3; // GET + POST + const INPUT_GPC = 7; // GET + POST + COOKIE + + + /** + * A wrapper for PHP's explode() that does not throw a warning + * when the separator does not exist in the string + * + * @param string $separator Separator string + * @param string $string The string to explode + * + * @return array Exploded string. Still an array if there's no separator in the string + */ + public static function explode($separator, $string) + { + if (strpos($string, $separator) !== false) { + return explode($separator, $string); + } + + return [$string, null]; + } + + /** + * Helper method to set a cookie with the current path and host settings + * + * @param string $name Cookie name + * @param string $value Cookie value + * @param int $exp Expiration time + * @param bool $http_only HTTP Only + */ + public static function setcookie($name, $value, $exp = 0, $http_only = true) + { + if (headers_sent()) { + return; + } + + $attrib = session_get_cookie_params(); + $attrib['expires'] = $exp; + $attrib['secure'] = $attrib['secure'] || self::https_check(); + $attrib['httponly'] = $http_only; + + // session_get_cookie_params() return includes 'lifetime' but setcookie() does not use it, instead it uses 'expires' + unset($attrib['lifetime']); + + setcookie($name, $value, $attrib); + } + + /** + * E-mail address validation. + * + * @param string $email Email address + * @param bool $dns_check True to check dns + * + * @return bool True on success, False if address is invalid + */ + public static function check_email($email, $dns_check = true) + { + // Check for invalid (control) characters + if (preg_match('/\p{Cc}/u', $email)) { + return false; + } + + // Check for length limit specified by RFC 5321 (#1486453) + if (strlen($email) > 254) { + return false; + } + + $pos = strrpos($email, '@'); + if (!$pos) { + return false; + } + + $domain_part = substr($email, $pos + 1); + $local_part = substr($email, 0, $pos); + + // quoted-string, make sure all backslashes and quotes are + // escaped + if (substr($local_part, 0, 1) == '"') { + $local_quoted = preg_replace('/\\\\(\\\\|\")/','', substr($local_part, 1, -1)); + if (preg_match('/\\\\|"/', $local_quoted)) { + return false; + } + } + // dot-atom portion, make sure there's no prohibited characters + else if (preg_match('/(^\.|\.\.|\.$)/', $local_part) + || preg_match('/[\\ ",:;<>@]/', $local_part) + ) { + return false; + } + + // Validate domain part + if (preg_match('/^\[((IPv6:[0-9a-f:.]+)|([0-9.]+))\]$/i', $domain_part, $matches)) { + return self::check_ip(preg_replace('/^IPv6:/i', '', $matches[1])); // valid IPv4 or IPv6 address + } + else { + // If not an IP address + $domain_array = explode('.', $domain_part); + // Not enough parts to be a valid domain + if (count($domain_array) < 2) { + return false; + } + + foreach ($domain_array as $part) { + if (!preg_match('/^((xn--)?([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part)) { + return false; + } + } + + // last domain part (allow extended TLD) + $last_part = array_pop($domain_array); + if (strpos($last_part, 'xn--') !== 0 + && (preg_match('/[^a-zA-Z0-9]/', $last_part) || preg_match('/^[0-9]+$/', $last_part)) + ) { + return false; + } + + $rcube = rcube::get_instance(); + + if (!$dns_check || !function_exists('checkdnsrr') || !$rcube->config->get('email_dns_check')) { + return true; + } + + // Check DNS record(s) + // Note: We can't use ANY (#6581) + foreach (['A', 'MX', 'CNAME', 'AAAA'] as $type) { + if (checkdnsrr($domain_part, $type)) { + return true; + } + } + } + + return false; + } + + /** + * Validates IPv4 or IPv6 address + * + * @param string $ip IP address in v4 or v6 format + * + * @return bool True if the address is valid + */ + public static function check_ip($ip) + { + return filter_var($ip, FILTER_VALIDATE_IP) !== false; + } + + /** + * Replacing specials characters to a specific encoding type + * + * @param string $str Input string + * @param string $enctype Encoding type: text|html|xml|js|url + * @param string $mode Replace mode for tags: show|remove|strict + * @param bool $newlines Convert newlines + * + * @return string The quoted string + */ + public static function rep_specialchars_output($str, $enctype = '', $mode = '', $newlines = true) + { + static $html_encode_arr = false; + static $js_rep_table = false; + static $xml_rep_table = false; + + if (!is_string($str)) { + $str = strval($str); + } + + // encode for HTML output + if ($enctype == 'html') { + if (!$html_encode_arr) { + $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS); + unset($html_encode_arr['?']); + } + + $encode_arr = $html_encode_arr; + + if ($mode == 'remove') { + $str = strip_tags($str); + } + else if ($mode != 'strict') { + // don't replace quotes and html tags + $ltpos = strpos($str, '<'); + if ($ltpos !== false && strpos($str, '>', $ltpos) !== false) { + unset($encode_arr['"']); + unset($encode_arr['<']); + unset($encode_arr['>']); + unset($encode_arr['&']); + } + } + + $out = strtr($str, $encode_arr); + + return $newlines ? nl2br($out) : $out; + } + + // if the replace tables for XML and JS are not yet defined + if ($js_rep_table === false) { + $js_rep_table = $xml_rep_table = []; + $xml_rep_table['&'] = '&'; + + // can be increased to support more charsets + for ($c=160; $c<256; $c++) { + $xml_rep_table[chr($c)] = "&#$c;"; + } + + $xml_rep_table['"'] = '"'; + $js_rep_table['"'] = '\\"'; + $js_rep_table["'"] = "\\'"; + $js_rep_table["\\"] = "\\\\"; + // Unicode line and paragraph separators (#1486310) + $js_rep_table[chr(hexdec('E2')).chr(hexdec('80')).chr(hexdec('A8'))] = '
'; + $js_rep_table[chr(hexdec('E2')).chr(hexdec('80')).chr(hexdec('A9'))] = '
'; + } + + // encode for javascript use + if ($enctype == 'js') { + return preg_replace(["/\r?\n/", "/\r/", '/<\\//'], ['\n', '\n', '<\\/'], strtr($str, $js_rep_table)); + } + + // encode for plaintext + if ($enctype == 'text') { + return str_replace("\r\n", "\n", $mode == 'remove' ? strip_tags($str) : $str); + } + + if ($enctype == 'url') { + return rawurlencode($str); + } + + // encode for XML + if ($enctype == 'xml') { + return strtr($str, $xml_rep_table); + } + + // no encoding given -> return original string + return $str; + } + + /** + * Read input value and make sure it is a string. + * + * @param string $fname Field name to read + * @param int $source Source to get value from (see self::INPUT_*) + * @param bool $allow_html Allow HTML tags in field value + * @param string $charset Charset to convert into + * + * @return string Request parameter value + * @see self::get_input_value() + */ + public static function get_input_string($fname, $source, $allow_html = false, $charset = null) + { + $value = self::get_input_value($fname, $source, $allow_html, $charset); + + return is_string($value) ? $value : ''; + } + + /** + * Read request parameter value and convert it for internal use + * Performs stripslashes() and charset conversion if necessary + * + * @param string $fname Field name to read + * @param int $source Source to get value from (see self::INPUT_*) + * @param bool $allow_html Allow HTML tags in field value + * @param string $charset Charset to convert into + * + * @return string|array|null Request parameter value or NULL if not set + */ + public static function get_input_value($fname, $source, $allow_html = false, $charset = null) + { + $value = null; + + if (($source & self::INPUT_GET) && isset($_GET[$fname])) { + $value = $_GET[$fname]; + } + + if (($source & self::INPUT_POST) && isset($_POST[$fname])) { + $value = $_POST[$fname]; + } + + if (($source & self::INPUT_COOKIE) && isset($_COOKIE[$fname])) { + $value = $_COOKIE[$fname]; + } + + return self::parse_input_value($value, $allow_html, $charset); + } + + /** + * Parse/validate input value. See self::get_input_value() + * Performs stripslashes() and charset conversion if necessary + * + * @param string $value Input value + * @param bool $allow_html Allow HTML tags in field value + * @param string $charset Charset to convert into + * + * @return string Parsed value + */ + public static function parse_input_value($value, $allow_html = false, $charset = null) + { + if (empty($value)) { + return $value; + } + + if (is_array($value)) { + foreach ($value as $idx => $val) { + $value[$idx] = self::parse_input_value($val, $allow_html, $charset); + } + + return $value; + } + + // remove HTML tags if not allowed + if (!$allow_html) { + $value = strip_tags($value); + } + + $rcube = rcube::get_instance(); + $output_charset = is_object($rcube->output) ? $rcube->output->get_charset() : null; + + // remove invalid characters (#1488124) + if ($output_charset == 'UTF-8') { + $value = rcube_charset::clean($value); + } + + // convert to internal charset + if ($charset && $output_charset) { + $value = rcube_charset::convert($value, $output_charset, $charset); + } + + return $value; + } + + /** + * Convert array of request parameters (prefixed with _) + * to a regular array with non-prefixed keys. + * + * @param int $mode Source to get value from (GPC) + * @param string $ignore PCRE expression to skip parameters by name + * @param bool $allow_html Allow HTML tags in field value + * + * @return array Hash array with all request parameters + */ + public static function request2param($mode = null, $ignore = 'task|action', $allow_html = false) + { + $out = []; + $src = $mode == self::INPUT_GET ? $_GET : ($mode == self::INPUT_POST ? $_POST : $_REQUEST); + + foreach (array_keys($src) as $key) { + $fname = $key[0] == '_' ? substr($key, 1) : $key; + if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) { + $out[$fname] = self::get_input_value($key, $mode, $allow_html); + } + } + + return $out; + } + + /** + * Convert the given string into a valid HTML identifier + * Same functionality as done in app.js with rcube_webmail.html_identifier() + * + * @param string $str String input + * @param bool $encode Use base64 encoding + * + * @return string Valid HTML identifier + */ + public static function html_identifier($str, $encode = false) + { + if ($encode) { + return rtrim(strtr(base64_encode($str), '+/', '-_'), '='); + } + + return asciiwords($str, true, '_'); + } + + /** + * Replace all css definitions with #container [def] + * and remove css-inlined scripting, make position style safe + * + * @param string $source CSS source code + * @param string $container_id Container ID to use as prefix + * @param bool $allow_remote Allow remote content + * @param string $prefix Prefix to be added to id/class identifier + * + * @return string Modified CSS source + */ + public static function mod_css_styles($source, $container_id, $allow_remote = false, $prefix = '') + { + $last_pos = 0; + $replacements = new rcube_string_replacer; + + // ignore the whole block if evil styles are detected + $source = self::xss_entity_decode($source); + $stripped = preg_replace('/[^a-z\(:;]/i', '', $source); + $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\((?!data:image)' : ''); + + if (preg_match("/$evilexpr/i", $stripped)) { + return '/* evil! */'; + } + + $strict_url_regexp = '!url\s*\(\s*["\']?(https?:)//[a-z0-9/._+-]+["\']?\s*\)!Uims'; + + // remove html comments + $source = preg_replace('/(^\s*<\!--)|(-->\s*$)/m', '', $source); + + // cut out all contents between { and } + while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { + $nested = strpos($source, '{', $pos+1); + if ($nested && $nested < $pos2) { // when dealing with nested blocks (e.g. @media), take the inner one + $pos = $nested; + } + $length = $pos2 - $pos - 1; + $styles = substr($source, $pos+1, $length); + $output = ''; + + // check every css rule in the style block... + foreach (self::parse_css_block($styles) as $rule) { + // Remove 'page' attributes (#7604) + if ($rule[0] == 'page') { + continue; + } + + // Convert position:fixed to position:absolute (#5264) + if ($rule[0] == 'position' && strcasecmp($rule[1], 'fixed') === 0) { + $rule[1] = 'absolute'; + } + else if ($allow_remote) { + $stripped = preg_replace('/[^a-z\(:;]/i', '', $rule[1]); + + // allow data:image and strict url() values only + if ( + stripos($stripped, 'url(') !== false + && stripos($stripped, 'url(data:image') === false + && !preg_match($strict_url_regexp, $rule[1]) + ) { + $rule[1] = '/* evil! */'; + } + } + + $output .= sprintf(" %s: %s;", $rule[0] , $rule[1]); + } + + $key = $replacements->add($output . ' '); + $repl = $replacements->get_replacement($key); + $source = substr_replace($source, $repl, $pos+1, $length); + $last_pos = $pos2 - ($length - strlen($repl)); + } + + // add #container to each tag selector and prefix to id/class identifiers + if ($container_id || $prefix) { + // Exclude rcube_string_replacer pattern matches, this is needed + // for cases like @media { body { position: fixed; } } (#5811) + $excl = '(?!' . substr($replacements->pattern, 1, -1) . ')'; + $regexp = '/(^\s*|,\s*|\}\s*|\{\s*)(' . $excl . ':?[a-z0-9\._#\*\[][a-z0-9\._:\(\)#=~ \[\]"\|\>\+\$\^-]*)/im'; + $callback = function($matches) use ($container_id, $prefix) { + $replace = $matches[2]; + + if (stripos($replace, ':root') === 0) { + $replace = substr($replace, 5); + } + + if ($prefix) { + $replace = str_replace(['.', '#'], [".$prefix", "#$prefix"], $replace); + } + + if ($container_id) { + $replace = "#$container_id " . $replace; + } + + // Remove redundant spaces (for simpler testing) + $replace = preg_replace('/\s+/', ' ', $replace); + + return str_replace($matches[2], $replace, $matches[0]); + }; + + $source = preg_replace_callback($regexp, $callback, $source); + } + + // replace body definition because we also stripped off the tag + if ($container_id) { + $regexp = '/#' . preg_quote($container_id, '/') . '\s+body/i'; + $source = preg_replace($regexp, "#$container_id", $source); + } + + // put block contents back in + $source = $replacements->resolve($source); + + return $source; + } + + /** + * Explode css style. Property names will be lower-cased and trimmed. + * Values will be trimmed. Invalid entries will be skipped. + * + * @param string $style CSS style + * + * @return array List of CSS rule pairs, e.g. [['color', 'red'], ['top', '0']] + */ + public static function parse_css_block($style) + { + $pos = 0; + + // first remove comments + while (($pos = strpos($style, '/*', $pos)) !== false) { + $end = strpos($style, '*/', $pos+2); + + if ($end === false) { + $style = substr($style, 0, $pos); + } + else { + $style = substr_replace($style, '', $pos, $end - $pos + 2); + } + } + + // Replace new lines with spaces + $style = preg_replace('/[\r\n]+/', ' ', $style); + + $style = trim($style); + $length = strlen($style); + $result = []; + $pos = 0; + + while ($pos < $length && ($colon_pos = strpos($style, ':', $pos))) { + // Property name + $name = strtolower(trim(substr($style, $pos, $colon_pos - $pos))); + + // get the property value + $q = $s = false; + for ($i = $colon_pos + 1; $i < $length; $i++) { + if (($style[$i] == "\"" || $style[$i] == "'") && ($i == 0 || $style[$i-1] != "\\")) { + if ($q == $style[$i]) { + $q = false; + } + else if ($q === false) { + $q = $style[$i]; + } + } + else if ($style[$i] == "(" && !$q && ($i == 0 || $style[$i-1] != "\\")) { + $q = "("; + } + else if ($style[$i] == ")" && $q == "(" && $style[$i-1] != "\\") { + $q = false; + } + + if ($q === false && (($s = $style[$i] == ';') || $i == $length - 1)) { + break; + } + } + + $value_length = $i - $colon_pos - ($s ? 1 : 0); + $value = trim(substr($style, $colon_pos + 1, $value_length)); + + if (strlen($name) && !preg_match('/[^a-z-]/', $name) && strlen($value) && $value !== ';') { + $result[] = [$name, $value]; + } + + $pos = $i + 1; + } + + return $result; + } + + /** + * Generate CSS classes from mimetype and filename extension + * + * @param string $mimetype Mimetype + * @param string $filename Filename + * + * @return string CSS classes separated by space + */ + public static function file2class($mimetype, $filename) + { + $mimetype = strtolower($mimetype); + $filename = strtolower($filename); + + list($primary, $secondary) = rcube_utils::explode('/', $mimetype); + + $classes = [$primary ?: 'unknown']; + + if (!empty($secondary)) { + $classes[] = $secondary; + } + + if (preg_match('/\.([a-z0-9]+)$/', $filename, $m)) { + if (!in_array($m[1], $classes)) { + $classes[] = $m[1]; + } + } + + return implode(' ', $classes); + } + + /** + * Decode escaped entities used by known XSS exploits. + * See http://downloads.securityfocus.com/vulnerabilities/exploits/26800.eml for examples + * + * @param string $content CSS content to decode + * + * @return string Decoded string + */ + public static function xss_entity_decode($content) + { + $callback = function($matches) { return chr(hexdec($matches[1])); }; + + $out = html_entity_decode(html_entity_decode($content)); + $out = trim(preg_replace('/(^$)/', '', trim($out))); + $out = preg_replace_callback('/\\\([0-9a-f]{2,6})\s*/i', $callback, $out); + $out = preg_replace('/\\\([^0-9a-f])/i', '\\1', $out); + $out = preg_replace('#/\*.*\*/#Ums', '', $out); + $out = strip_tags($out); + + return $out; + } + + /** + * Check if we can process not exceeding memory_limit + * + * @param int $need Required amount of memory + * + * @return bool True if memory won't be exceeded, False otherwise + */ + public static function mem_check($need) + { + $mem_limit = parse_bytes(ini_get('memory_limit')); + $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB + + return $mem_limit > 0 && $memory + $need > $mem_limit ? false : true; + } + + /** + * Check if working in SSL mode + * + * @param int $port HTTPS port number + * @param bool $use_https Enables 'use_https' option checking + * + * @return bool True in SSL mode, False otherwise + */ + public static function https_check($port = null, $use_https = true) + { + if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') { + return true; + } + + if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) + && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https' + && self::check_proxy_whitelist_ip() + ) { + return true; + } + + if ($port && isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == $port) { + return true; + } + + if ($use_https && rcube::get_instance()->config->get('use_https')) { + return true; + } + + return false; + } + + /** + * Check if the reported REMOTE_ADDR is in the 'proxy_whitelist' config option + */ + public static function check_proxy_whitelist_ip() { + return in_array($_SERVER['REMOTE_ADDR'], (array) rcube::get_instance()->config->get('proxy_whitelist', [])); + } + + /** + * Replaces hostname variables. + * + * @param string $name Hostname + * @param string $host Optional IMAP hostname + * + * @return string Hostname + */ + public static function parse_host($name, $host = '') + { + if (!is_string($name)) { + return $name; + } + + // %n - host + $n = self::server_name(); + // %t - host name without first part, e.g. %n=mail.domain.tld, %t=domain.tld + // If %n=domain.tld then %t=domain.tld as well (remains valid) + $t = preg_replace('/^[^.]+\.(?![^.]+$)/', '', $n); + // %d - domain name without first part (up to domain.tld) + $d = preg_replace('/^[^.]+\.(?![^.]+$)/', '', self::server_name('HTTP_HOST')); + // %h - IMAP host + $h = !empty($_SESSION['storage_host']) ? $_SESSION['storage_host'] : $host; + // %z - IMAP domain without first part, e.g. %h=imap.domain.tld, %z=domain.tld + // If %h=domain.tld then %z=domain.tld as well (remains valid) + $z = preg_replace('/^[^.]+\.(?![^.]+$)/', '', $h); + // %s - domain name after the '@' from e-mail address provided at login screen. + // Returns FALSE if an invalid email is provided + $s = ''; + if (strpos($name, '%s') !== false) { + $user_email = self::idn_to_ascii(self::get_input_value('_user', self::INPUT_POST)); + $matches = preg_match('/(.*)@([a-z0-9\.\-\[\]\:]+)/i', $user_email, $s); + if ($matches < 1 || filter_var($s[1]."@".$s[2], FILTER_VALIDATE_EMAIL) === false) { + return false; + } + $s = $s[2]; + } + + return str_replace(['%n', '%t', '%d', '%h', '%z', '%s'], [$n, $t, $d, $h, $z, $s], $name); + } + + /** + * Parse host specification URI. + * + * @param string $host Host URI + * @param int $plain_port Plain port number + * @param int $ssl_port SSL port number + * + * @return array An array with three elements (hostname, scheme, port) + */ + public static function parse_host_uri($host, $plain_port = null, $ssl_port = null) + { + if (preg_match('#^(unix|ldapi)://#i', $host, $matches)) { + return [$host, $matches[1], -1]; + } + + $url = parse_url($host); + $port = $plain_port; + $scheme = null; + + if (!empty($url['host'])) { + $host = $url['host']; + $scheme = $url['scheme'] ?? null; + + if (!empty($url['port'])) { + $port = $url['port']; + } + else if ( + $scheme + && $ssl_port + && ($scheme === 'ssl' || ($scheme != 'tls' && $scheme[strlen($scheme) - 1] === 's')) + ) { + // assign SSL port to ssl://, imaps://, ldaps://, but not tls:// + $port = $ssl_port; + } + } + + return [$host, $scheme, $port]; + } + + /** + * Returns the server name after checking it against trusted hostname patterns. + * + * Returns 'localhost' and logs a warning when the hostname is not trusted. + * + * @param string $type The $_SERVER key, e.g. 'HTTP_HOST', Default: 'SERVER_NAME'. + * @param bool $strip_port Strip port from the host name + * + * @return string Server name + */ + public static function server_name($type = null, $strip_port = true) + { + if (!$type) { + $type = 'SERVER_NAME'; + } + + $name = $_SERVER[$type] ?? ''; + $rcube = rcube::get_instance(); + $patterns = (array) $rcube->config->get('trusted_host_patterns'); + + if (!empty($name)) { + if ($strip_port) { + $name = preg_replace('/:\d+$/', '', $name); + } + + if (empty($patterns)) { + return $name; + } + + foreach ($patterns as $pattern) { + // the pattern might be a regular expression or just a host/domain name + if (preg_match('/[^a-zA-Z0-9.:-]/', $pattern)) { + if (preg_match("/$pattern/", $name)) { + return $name; + } + } + else if (strtolower($name) === strtolower($pattern)) { + return $name; + } + } + + $rcube->raise_error([ + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Specified host is not trusted. Using 'localhost'." + ] + , true, false + ); + } + + return 'localhost'; + } + + /** + * Returns remote IP address and forwarded addresses if found + * + * @return string Remote IP address(es) + */ + public static function remote_ip() + { + $address = $_SERVER['REMOTE_ADDR'] ?? ''; + + // append the NGINX X-Real-IP header, if set + if (!empty($_SERVER['HTTP_X_REAL_IP']) && $_SERVER['HTTP_X_REAL_IP'] != $address) { + $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP']; + } + + // append the X-Forwarded-For header, if set + if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR']; + } + + if (!empty($remote_ip)) { + $address .= ' (' . implode(',', $remote_ip) . ')'; + } + + return $address; + } + + /** + * Returns the real remote IP address + * + * @return string Remote IP address + */ + public static function remote_addr() + { + // Check if any of the headers are set first to improve performance + if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) || !empty($_SERVER['HTTP_X_REAL_IP'])) { + $proxy_whitelist = (array) rcube::get_instance()->config->get('proxy_whitelist', []); + if (in_array($_SERVER['REMOTE_ADDR'], $proxy_whitelist)) { + if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + foreach (array_reverse(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])) as $forwarded_ip) { + $forwarded_ip = trim($forwarded_ip); + if (!in_array($forwarded_ip, $proxy_whitelist)) { + return $forwarded_ip; + } + } + } + + if (!empty($_SERVER['HTTP_X_REAL_IP'])) { + return $_SERVER['HTTP_X_REAL_IP']; + } + } + } + + if (!empty($_SERVER['REMOTE_ADDR'])) { + return $_SERVER['REMOTE_ADDR']; + } + + return ''; + } + + /** + * Read a specific HTTP request header. + * + * @param string $name Header name + * + * @return string|null Header value or null if not available + */ + public static function request_header($name) + { + if (function_exists('apache_request_headers')) { + $headers = apache_request_headers(); + $key = strtoupper($name); + } + else { + $headers = $_SERVER; + $key = 'HTTP_' . strtoupper(strtr($name, '-', '_')); + } + + if (!empty($headers)) { + $headers = array_change_key_case($headers, CASE_UPPER); + + return $headers[$key] ?? null; + } + } + + /** + * Explode quoted string + * + * @param string $delimiter Delimiter expression string for preg_match() + * @param string $string Input string + * + * @return array String items + */ + public static function explode_quoted_string($delimiter, $string) + { + $result = []; + $strlen = strlen($string); + + for ($q=$p=$i=0; $i < $strlen; $i++) { + if ($string[$i] == "\"" && (!isset($string[$i-1]) || $string[$i-1] != "\\")) { + $q = $q ? false : true; + } + else if (!$q && preg_match("/$delimiter/", $string[$i])) { + $result[] = substr($string, $p, $i - $p); + $p = $i + 1; + } + } + + $result[] = (string) substr($string, $p); + + return $result; + } + + /** + * Improved equivalent to strtotime() + * + * @param string $date Date string + * @param DateTimeZone $timezone Timezone to use for DateTime object + * + * @return int Unix timestamp + */ + public static function strtotime($date, $timezone = null) + { + $date = self::clean_datestr($date); + $tzname = $timezone ? ' ' . $timezone->getName() : ''; + + // unix timestamp + if (is_numeric($date)) { + return (int) $date; + } + + // It can be very slow when provided string is not a date and very long + if (strlen($date) > 128) { + $date = substr($date, 0, 128); + } + + // if date parsing fails, we have a date in non-rfc format. + // remove token from the end and try again + while (($ts = @strtotime($date . $tzname)) === false || $ts < 0) { + if (($pos = strrpos($date, ' ')) === false) { + break; + } + + $date = rtrim(substr($date, 0, $pos)); + } + + return (int) $ts; + } + + /** + * Date parsing function that turns the given value into a DateTime object + * + * @param string $date Date string + * @param DateTimeZone $timezone Timezone to use for DateTime object + * + * @return DateTime|false DateTime object or False on failure + */ + public static function anytodatetime($date, $timezone = null) + { + if ($date instanceof DateTime) { + return $date; + } + + $dt = false; + $date = self::clean_datestr($date); + + // try to parse string with DateTime first + if (!empty($date)) { + try { + $_date = preg_match('/^[0-9]+$/', $date) ? "@$date" : $date; + $dt = $timezone ? new DateTime($_date, $timezone) : new DateTime($_date); + } + catch (Exception $e) { + // ignore + } + } + + // try our advanced strtotime() method + if (!$dt && ($timestamp = self::strtotime($date, $timezone))) { + try { + $dt = new DateTime("@".$timestamp); + if ($timezone) { + $dt->setTimezone($timezone); + } + } + catch (Exception $e) { + // ignore + } + } + + return $dt; + } + + /** + * Clean up date string for strtotime() input + * + * @param string $date Date string + * + * @return string Date string + */ + public static function clean_datestr($date) + { + $date = trim((string) $date); + + // check for MS Outlook vCard date format YYYYMMDD + if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) { + return sprintf('%04d-%02d-%02d 00:00:00', intval($m[1]), intval($m[2]), intval($m[3])); + } + + // Clean malformed data + $date = preg_replace( + [ + '/\(.*\)/', // remove RFC comments + '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal + '/[^a-z0-9\x20\x09:\/\.+-]/i', // remove any invalid characters + '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names + ], + [ + '', + '\\1', + '', + '', + ], + $date + ); + + $date = trim($date); + + // try to fix dd/mm vs. mm/dd discrepancy, we can't do more here + if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})(\s.*)?$/', $date, $m)) { + $mdy = $m[2] > 12 && $m[1] <= 12; + $day = $mdy ? $m[2] : $m[1]; + $month = $mdy ? $m[1] : $m[2]; + $date = sprintf('%04d-%02d-%02d%s', $m[3], $month, $day, $m[4] ?? ' 00:00:00'); + } + // I've found that YYYY.MM.DD is recognized wrong, so here's a fix + else if (preg_match('/^(\d{4})\.(\d{1,2})\.(\d{1,2})(\s.*)?$/', $date, $m)) { + $date = sprintf('%04d-%02d-%02d%s', $m[1], $m[2], $m[3], $m[4] ?? ' 00:00:00'); + } + + return $date; + } + + /** + * Turns the given date-only string in defined format into YYYY-MM-DD format. + * + * Supported formats: 'Y/m/d', 'Y.m.d', 'd-m-Y', 'd/m/Y', 'd.m.Y', 'j.n.Y' + * + * @param string $date Date string + * @param string $format Input date format + * + * @return string Date string in YYYY-MM-DD format, or the original string + * if format is not supported + */ + public static function format_datestr($date, $format) + { + $format_items = preg_split('/[.-\/\\\\]/', $format); + $date_items = preg_split('/[.-\/\\\\]/', $date); + $iso_format = '%04d-%02d-%02d'; + + if (count($format_items) == 3 && count($date_items) == 3) { + if ($format_items[0] == 'Y') { + $date = sprintf($iso_format, $date_items[0], $date_items[1], $date_items[2]); + } + else if (strpos('dj', $format_items[0]) !== false) { + $date = sprintf($iso_format, $date_items[2], $date_items[1], $date_items[0]); + } + else if (strpos('mn', $format_items[0]) !== false) { + $date = sprintf($iso_format, $date_items[2], $date_items[0], $date_items[1]); + } + } + + return $date; + } + + /** + * Wrapper for idn_to_ascii with support for e-mail address. + * + * Warning: Domain names may be lowercase'd. + * Warning: An empty string may be returned on invalid domain. + * + * @param string $str Decoded e-mail address + * + * @return string Encoded e-mail address + */ + public static function idn_to_ascii($str) + { + return self::idn_convert($str, true); + } + + /** + * Wrapper for idn_to_utf8 with support for e-mail address + * + * @param string $str Decoded e-mail address + * + * @return string Encoded e-mail address + */ + public static function idn_to_utf8($str) + { + return self::idn_convert($str, false); + } + + /** + * Convert a string to ascii or utf8 (using IDNA standard) + * + * @param string $input Decoded e-mail address + * @param bool $is_utf Convert by idn_to_ascii if true and idn_to_utf8 if false + * + * @return string Encoded e-mail address + */ + public static function idn_convert($input, $is_utf = false) + { + if ($at = strpos($input, '@')) { + $user = substr($input, 0, $at); + $domain = substr($input, $at + 1); + } + else { + $user = ''; + $domain = $input; + } + + // Note that in PHP 7.2/7.3 calling idn_to_* functions with default arguments + // throws a warning, so we have to set the variant explicitly (#6075) + $variant = INTL_IDNA_VARIANT_UTS46; + $options = 0; + + // Because php-intl extension lowercases domains and return false + // on invalid input (#6224), we skip conversion when not needed + + if ($is_utf) { + if (preg_match('/[^\x20-\x7E]/', $domain)) { + $options = IDNA_NONTRANSITIONAL_TO_ASCII; + $domain = idn_to_ascii($domain, $options, $variant); + } + } + else if (preg_match('/(^|\.)xn--/i', $domain)) { + $options = IDNA_NONTRANSITIONAL_TO_UNICODE; + $domain = idn_to_utf8($domain, $options, $variant); + } + + if ($domain === false) { + return ''; + } + + return $at ? $user . '@' . $domain : $domain; + } + + /** + * Split the given string into word tokens + * + * @param string $str Input to tokenize + * @param int $minlen Minimum length of a single token + * + * @return array List of tokens + */ + public static function tokenize_string($str, $minlen = 2) + { + if (!is_string($str)) { + return []; + } + + $expr = ['/[\s;,"\'\/+-]+/ui', '/(\d)[-.\s]+(\d)/u']; + $repl = [' ', '\\1\\2']; + + if ($minlen > 1) { + $minlen--; + $expr[] = "/(^|\s+)\w{1,$minlen}(\s+|$)/u"; + $repl[] = ' '; + } + + $str = preg_replace($expr, $repl, $str); + + return is_string($str) ? array_filter(explode(" ", $str)) : []; + } + + /** + * Normalize the given string for fulltext search. + * Currently only optimized for ISO-8859-1 and ISO-8859-2 characters; to be extended + * + * @param string $str Input string (UTF-8) + * @param bool $as_array True to return list of words as array + * @param int $minlen Minimum length of tokens + * + * @return string|array Normalized string or a list of normalized tokens + */ + public static function normalize_string($str, $as_array = false, $minlen = 2) + { + // replace 4-byte unicode characters with '?' character, + // these are not supported in default utf-8 charset on mysql, + // the chance we'd need them in searching is very low + $str = preg_replace('/(' + . '\xF0[\x90-\xBF][\x80-\xBF]{2}' + . '|[\xF1-\xF3][\x80-\xBF]{3}' + . '|\xF4[\x80-\x8F][\x80-\xBF]{2}' + . ')/', '?', $str); + + // split by words + $arr = self::tokenize_string($str, $minlen); + + // detect character set + if (rcube_charset::convert(rcube_charset::convert($str, 'UTF-8', 'ISO-8859-1'), 'ISO-8859-1', 'UTF-8') == $str) { + // ISO-8859-1 (or ASCII) + preg_match_all('/./u', 'äâàåáãæçéêëèïîìíñöôòøõóüûùúýÿ', $keys); + preg_match_all('/./', 'aaaaaaaceeeeiiiinoooooouuuuyy', $values); + + $mapping = array_combine($keys[0], $values[0]); + $mapping = array_merge($mapping, ['ß' => 'ss', 'ae' => 'a', 'oe' => 'o', 'ue' => 'u']); + } + else if (rcube_charset::convert(rcube_charset::convert($str, 'UTF-8', 'ISO-8859-2'), 'ISO-8859-2', 'UTF-8') == $str) { + // ISO-8859-2 + preg_match_all('/./u', 'ąáâäćçčéęëěíîłľĺńňóôöŕřśšşťţůúűüźžżý', $keys); + preg_match_all('/./', 'aaaaccceeeeiilllnnooorrsssttuuuuzzzy', $values); + + $mapping = array_combine($keys[0], $values[0]); + $mapping = array_merge($mapping, ['ß' => 'ss', 'ae' => 'a', 'oe' => 'o', 'ue' => 'u']); + } + + foreach ($arr as $i => $part) { + $part = mb_strtolower($part); + + if (!empty($mapping)) { + $part = strtr($part, $mapping); + } + + $arr[$i] = $part; + } + + return $as_array ? $arr : implode(' ', $arr); + } + + /** + * Compare two strings for matching words (order not relevant) + * + * @param string $haystack Haystack + * @param string $needle Needle + * + * @return bool True if match, False otherwise + */ + public static function words_match($haystack, $needle) + { + $a_needle = self::tokenize_string($needle, 1); + $_haystack = implode(' ', self::tokenize_string($haystack, 1)); + $valid = strlen($_haystack) > 0; + $hits = 0; + + foreach ($a_needle as $w) { + if ($valid) { + if (stripos($_haystack, $w) !== false) { + $hits++; + } + } + else if (stripos($haystack, $w) !== false) { + $hits++; + } + } + + return $hits >= count($a_needle); + } + + /** + * Parse commandline arguments into a hash array + * + * @param array $aliases Argument alias names + * + * @return array Argument values hash + */ + public static function get_opt($aliases = []) + { + $args = []; + $bool = []; + + // find boolean (no value) options + foreach ($aliases as $key => $alias) { + if ($pos = strpos($alias, ':')) { + $aliases[$key] = substr($alias, 0, $pos); + $bool[] = $key; + $bool[] = $aliases[$key]; + } + } + + for ($i=1; $i < count($_SERVER['argv']); $i++) { + $arg = $_SERVER['argv'][$i]; + $value = true; + $key = null; + + if (strlen($arg) && $arg[0] == '-') { + $key = preg_replace('/^-+/', '', $arg); + $sp = strpos($arg, '='); + + if ($sp > 0) { + $key = substr($key, 0, $sp - 2); + $value = substr($arg, $sp+1); + } + else if (in_array($key, $bool)) { + $value = true; + } + else if ( + isset($_SERVER['argv'][$i + 1]) + && strlen($_SERVER['argv'][$i + 1]) + && $_SERVER['argv'][$i + 1][0] != '-' + ) { + $value = $_SERVER['argv'][++$i]; + } + + $args[$key] = is_string($value) ? preg_replace(['/^["\']/', '/["\']$/'], '', $value) : $value; + } + else { + $args[] = $arg; + } + + if (!empty($aliases[$key])) { + $alias = $aliases[$key]; + $args[$alias] = $args[$key]; + } + } + + return $args; + } + + /** + * Safe password prompt for command line + * from http://blogs.sitepoint.com/2009/05/01/interactive-cli-password-prompt-in-php/ + * + * @param string $prompt Prompt text + * + * @return string Password + */ + public static function prompt_silent($prompt = "Password:") + { + if (preg_match('/^win/i', PHP_OS)) { + $vbscript = sys_get_temp_dir() . 'prompt_password.vbs'; + $vbcontent = 'wscript.echo(InputBox("' . addslashes($prompt) . '", "", "password here"))'; + file_put_contents($vbscript, $vbcontent); + + $command = "cscript //nologo " . escapeshellarg($vbscript); + $password = rtrim(shell_exec($command)); + unlink($vbscript); + + return $password; + } + + $command = "/usr/bin/env bash -c 'echo OK'"; + + if (rtrim(shell_exec($command)) !== 'OK') { + echo $prompt; + $pass = trim(fgets(STDIN)); + echo chr(8)."\r" . $prompt . str_repeat("*", strlen($pass))."\n"; + + return $pass; + } + + $command = "/usr/bin/env bash -c 'read -s -p \"" . addslashes($prompt) . "\" mypassword && echo \$mypassword'"; + $password = rtrim(shell_exec($command)); + echo "\n"; + + return $password; + } + + /** + * Find out if the string content means true or false + * + * @param string $str Input value + * + * @return bool Boolean value + */ + public static function get_boolean($str) + { + $str = strtolower((string) $str); + + return !in_array($str, ['false', '0', 'no', 'off', 'nein', ''], true); + } + + /** + * OS-dependent absolute path detection + * + * @param string $path File path + * + * @return bool True if the path is absolute, False otherwise + */ + public static function is_absolute_path($path) + { + if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { + return (bool) preg_match('!^[a-z]:[\\\\/]!i', $path); + } + + return isset($path[0]) && $path[0] == '/'; + } + + /** + * Resolve relative URL + * + * @param string $url Relative URL + * + * @return string Absolute URL + */ + public static function resolve_url($url) + { + // prepend protocol://hostname:port + if (!preg_match('|^https?://|', $url)) { + $schema = 'http'; + $default_port = 80; + + if (self::https_check()) { + $schema = 'https'; + $default_port = 443; + } + + $host = $_SERVER['HTTP_HOST'] ?? ''; + $port = $_SERVER['SERVER_PORT'] ?? 0; + + $prefix = $schema . '://' . preg_replace('/:\d+$/', '', $host); + if ($port && $port != $default_port && $port != 80) { + $prefix .= ':' . $port; + } + + $url = $prefix . ($url[0] == '/' ? '' : '/') . $url; + } + + return $url; + } + + /** + * Generate a random string + * + * @param int $length String length + * @param bool $raw Return RAW data instead of ascii + * + * @return string The generated random string + */ + public static function random_bytes($length, $raw = false) + { + // Use PHP7 true random generator + if ($raw) { + return random_bytes($length); + } + + $hextab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + $tabsize = strlen($hextab); + + $result = ''; + while ($length-- > 0) { + $result .= $hextab[random_int(0, $tabsize - 1)]; + } + + return $result; + } + + /** + * Convert binary data into readable form (containing a-zA-Z0-9 characters) + * + * @param string $input Binary input + * + * @return string Readable output (Base62) + * @deprecated since 1.3.1 + */ + public static function bin2ascii($input) + { + $hextab = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + $result = ''; + + for ($x = 0; $x < strlen($input); $x++) { + $result .= $hextab[ord($input[$x]) % 62]; + } + + return $result; + } + + /** + * Format current date according to specified format. + * This method supports microseconds (u). + * + * @param string $format Date format (default: 'd-M-Y H:i:s O') + * + * @return string Formatted date + */ + public static function date_format($format = null) + { + if (empty($format)) { + $format = 'd-M-Y H:i:s O'; + } + + if (strpos($format, 'u') !== false) { + $dt = number_format(microtime(true), 6, '.', ''); + + try { + $date = date_create_from_format('U.u', $dt); + $date->setTimeZone(new DateTimeZone(date_default_timezone_get())); + + return $date->format($format); + } + catch (Exception $e) { + // ignore, fallback to date() + } + } + + return date($format); + } + + /** + * Parses socket options and returns options for specified hostname. + * + * @param array &$options Configured socket options + * @param string $host Hostname + */ + public static function parse_socket_options(&$options, $host = null) + { + if (empty($host) || empty($options)) { + return; + } + + // get rid of schema and port from the hostname + $host_url = parse_url($host); + if (isset($host_url['host'])) { + $host = $host_url['host']; + } + + // find per-host options + if ($host && array_key_exists($host, $options)) { + $options = $options[$host]; + } + } + + /** + * Get maximum upload size + * + * @return int Maximum size in bytes + */ + public static function max_upload_size() + { + // find max filesize value + $max_filesize = parse_bytes(ini_get('upload_max_filesize')); + $max_postsize = parse_bytes(ini_get('post_max_size')); + + if ($max_postsize && $max_postsize < $max_filesize) { + $max_filesize = $max_postsize; + } + + return $max_filesize; + } + + /** + * Detect and log last PREG operation error + * + * @param array $error Error data (line, file, code, message) + * @param bool $terminate Stop script execution + * + * @return bool True on error, False otherwise + */ + public static function preg_error($error = [], $terminate = false) + { + if (($preg_error = preg_last_error()) != PREG_NO_ERROR) { + $errstr = "PCRE Error: $preg_error."; + + if (function_exists('preg_last_error_msg')) { + $errstr .= ' ' . preg_last_error_msg(); + } + + if ($preg_error == PREG_BACKTRACK_LIMIT_ERROR) { + $errstr .= " Consider raising pcre.backtrack_limit!"; + } + if ($preg_error == PREG_RECURSION_LIMIT_ERROR) { + $errstr .= " Consider raising pcre.recursion_limit!"; + } + + $error = array_merge(['code' => 620, 'line' => __LINE__, 'file' => __FILE__], $error); + + if (!empty($error['message'])) { + $error['message'] .= ' ' . $errstr; + } + else { + $error['message'] = $errstr; + } + + rcube::raise_error($error, true, $terminate); + + return true; + } + + return false; + } + + /** + * Generate a temporary file path in the Roundcube temp directory + * + * @param string $file_name String identifier for the type of temp file + * @param bool $unique Generate unique file names based on $file_name + * @param bool $create Create the temp file or not + * + * @return string temporary file path + */ + public static function temp_filename($file_name, $unique = true, $create = true) + { + $temp_dir = rcube::get_instance()->config->get('temp_dir'); + + // Fall back to system temp dir if configured dir is not writable + if (!is_writable($temp_dir)) { + $temp_dir = sys_get_temp_dir(); + } + + // On Windows tempnam() uses only the first three characters of prefix so use uniqid() and manually add the prefix + // Full prefix is required for garbage collection to recognise the file + $temp_file = $unique ? str_replace('.', '', uniqid($file_name, true)) : $file_name; + $temp_path = unslashify($temp_dir) . '/' . RCUBE_TEMP_FILE_PREFIX . $temp_file; + + // Sanity check for unique file name + if ($unique && file_exists($temp_path)) { + return self::temp_filename($file_name, $unique, $create); + } + + // Create the file to prevent possible race condition like tempnam() does + if ($create) { + touch($temp_path); + } + + return $temp_path; + } + + /** + * Clean the subject from reply and forward prefix + * + * @param string $subject Subject to clean + * @param string $mode Mode of cleaning : reply, forward or both + * + * @return string Cleaned subject + */ + public static function remove_subject_prefix($subject, $mode = 'both') + { + $config = rcmail::get_instance()->config; + + // Clean subject prefix for reply, forward or both + if ($mode == 'both') { + $reply_prefixes = $config->get('subject_reply_prefixes', ['Re:']); + $forward_prefixes = $config->get('subject_forward_prefixes', ['Fwd:', 'Fw:']); + $prefixes = array_merge($reply_prefixes, $forward_prefixes); + } + else if ($mode == 'reply') { + $prefixes = $config->get('subject_reply_prefixes', ['Re:']); + // replace (was: ...) (#1489375) + $subject = preg_replace('/\s*\([wW]as:[^\)]+\)\s*$/', '', $subject); + } + else if ($mode == 'forward') { + $prefixes = $config->get('subject_forward_prefixes', ['Fwd:', 'Fw:']); + } + + // replace Re:, Re[x]:, Re-x (#1490497) + $pieces = array_map(function($prefix) { + $prefix = strtolower(str_replace(':', '', $prefix)); + return "$prefix:|$prefix\[\d\]:|$prefix-\d:"; + }, $prefixes); + $pattern = '/^('.implode('|', $pieces).')\s*/i'; + do { + $subject = preg_replace($pattern, '', $subject, -1, $count); + } + while ($count); + + return trim($subject); + } +} diff --git a/admin/tool/messageinbound/roundcube/readme_moodle.txt b/admin/tool/messageinbound/roundcube/readme_moodle.txt new file mode 100644 index 00000000000..571c6f90238 --- /dev/null +++ b/admin/tool/messageinbound/roundcube/readme_moodle.txt @@ -0,0 +1,24 @@ +Description of Roundcube Framework 1.6.6 library import into Moodle + +We now use the client part of Roundcube Framework as a library in Moodle. +This library is used to receive emails from Moodle. +This library is not used to send emails. + +For more information on this version of Roundcube Framework, check out https://github.com/roundcube/roundcubemail/releases/tag/1.6.6 + +To upgrade this library: +1. Download the latest release of Roundcube Framework (roundcube-framework-xxx-tar.gz) in https://github.com/roundcube/roundcubemail/releases. +2. Extract the contents of the release archive to a temp folder. +3. Copy the following files from the temp folder to the Moodle folder admin/tool/messageinbound/roundcube: + - rcube_charset.php + - rcube_imap_generic.php + - rcube_message_header.php + - rcube_mime.php + - rcube_result_index.php + - rcube_result_thread.php + - rcube_utils.php +4. Find and replace all array_first() calls with array_shift() in the following files: + - rcube_imap_generic.php + - rcube_result_index.php + - rcube_result_thread.php +5. Update admin/tool/messageinbound/thirdpartylibs.xml. diff --git a/admin/tool/messageinbound/thirdpartylibs.xml b/admin/tool/messageinbound/thirdpartylibs.xml new file mode 100644 index 00000000000..e8be5ba5ee7 --- /dev/null +++ b/admin/tool/messageinbound/thirdpartylibs.xml @@ -0,0 +1,14 @@ + + + + roundcube + Roundcube Framework + GPL + 3.0+ + 1.6.6 + https://github.com/roundcube/roundcubemail + + The Roundcube Dev Team + + + diff --git a/lib/classes/component.php b/lib/classes/component.php index 880d2847a73..bc13015f3a7 100644 --- a/lib/classes/component.php +++ b/lib/classes/component.php @@ -88,7 +88,6 @@ class core_component { protected static $filestomap = ['lib.php', 'settings.php']; /** @var array associative array of PSR-0 namespaces and corresponding paths. */ protected static $psr0namespaces = [ - 'Horde' => 'lib/horde/framework/Horde', 'Mustache' => 'lib/mustache/src/Mustache', 'CFPropertyList' => 'lib/plist/classes/CFPropertyList', ]; diff --git a/lib/horde/framework/Horde/Array.php b/lib/horde/framework/Horde/Array.php deleted file mode 100644 index 147199d3f30..00000000000 --- a/lib/horde/framework/Horde/Array.php +++ /dev/null @@ -1,147 +0,0 @@ - - * @author Marko Djukic - * @author Jan Schneider - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Util - */ -class Horde_Array -{ - /** - * Sorts an array on a specified key. If the key does not exist, - * defaults to the first key of the array. - * - * @param array &$array The array to be sorted, passed by reference. - * @param string $key The key by which to sort. If not specified then - * the first key is used. - * @param integer $dir Sort direction: - * 0 = ascending (default) - * 1 = descending - * @param boolean $assoc Keep key value association? - */ - public static function arraySort(array &$array, $key = null, $dir = 0, - $assoc = true) - { - /* Return if the array is empty. */ - if (empty($array)) { - return; - } - - /* If no key to sort by is specified, use the first key of the - * first element. */ - if (is_null($key)) { - $keys = array_keys(reset($array)); - $key = array_shift($keys); - } - - /* Call the appropriate sort function. */ - $helper = new Horde_Array_Sort_Helper(); - $helper->key = $key; - $function = $dir ? 'reverseCompare' : 'compare'; - if ($assoc) { - uasort($array, array($helper, $function)); - } else { - usort($array, array($helper, $function)); - } - } - - /** - * Given an HTML type array field "example[key1][key2][key3]" breaks up - * the keys so that they could be used to reference a regular PHP array. - * - * @param string $field The field name to be examined. - * @param string &$base Will be set to the base element. - * @param array &$keys Will be set to the list of keys. - * - * @return boolean True on sucess, false on error. - */ - public static function getArrayParts($field, &$base, &$keys) - { - if (!preg_match('|([^\[]*)((\[[^\[\]]*\])+)|', $field, $matches)) { - return false; - } - - $base = $matches[1]; - $keys = explode('][', $matches[2]); - $keys[0] = substr($keys[0], 1); - $keys[count($keys) - 1] = substr($keys[count($keys) - 1], 0, strlen($keys[count($keys) - 1]) - 1); - return true; - } - - /** - * Using an array of keys iterate through the array following the - * keys to find the final key value. If a value is passed then set - * that value. - * - * @param array &$array The array to be used. - * @param array &$keys The key path to follow as an array. - * @param array $value If set the target element will have this value set - * to it. - * - * @return mixed The final value of the key path. - */ - public static function getElement(&$array, array &$keys, $value = null) - { - if (count($keys)) { - $key = array_shift($keys); - return isset($array[$key]) - ? self::getElement($array[$key], $keys, $value) - : false; - } - - if (!is_null($value)) { - $array = $value; - } - - return $array; - } - - /** - * Returns a rectangle of a two-dimensional array. - * - * @param array $array The array to extract the rectangle from. - * @param integer $row The start row of the rectangle. - * @param integer $col The start column of the rectangle. - * @param integer $height The height of the rectangle. - * @param integer $width The width of the rectangle. - * - * @return array The extracted rectangle. - */ - public static function getRectangle(array $array, $row, $col, $height, - $width) - { - $rec = array(); - for ($y = $row; $y < $row + $height; $y++) { - $rec[] = array_slice($array[$y], $col, $width); - } - return $rec; - } - - /** - * Given an array, returns an associative array with each element key - * derived from its value. - * For example: - * array(0 => 'foo', 1 => 'bar') - * would become: - * array('foo' => 'foo', 'bar' => 'bar') - * - * @param array $array An array of values. - * - * @return array An array with keys the same as values. - */ - public static function valuesToKeys(array $array) - { - return $array - ? array_combine($array, $array) - : array(); - } -} diff --git a/lib/horde/framework/Horde/Array/Sort/Helper.php b/lib/horde/framework/Horde/Array/Sort/Helper.php deleted file mode 100644 index 586518ea4f0..00000000000 --- a/lib/horde/framework/Horde/Array/Sort/Helper.php +++ /dev/null @@ -1,77 +0,0 @@ - - * @author Jan Schneider - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Util - */ -class Horde_Array_Sort_Helper -{ - /** - * The array key to sort by. - * - * @var string - */ - public $key; - - /** - * Compare two associative arrays by the array key defined in self::$key. - * - * @param array $a - * @param array $b - */ - public function compare($a, $b) - { - return strcoll(Horde_String::lower($a[$this->key], true, 'UTF-8'), Horde_String::lower($b[$this->key], true, 'UTF-8')); - } - - /** - * Compare, in reverse order, two associative arrays by the array key - * defined in self::$key. - * - * @param scalar $a TODO - * @param scalar $b TODO - * - * @return TODO - */ - public function reverseCompare($a, $b) - { - return strcoll(Horde_String::lower($b[$this->key], true, 'UTF-8'), Horde_String::lower($a[$this->key], true, 'UTF-8')); - } - - /** - * Compare array keys case insensitively for uksort. - * - * @param scalar $a TODO - * @param scalar $b TODO - * - * @return TODO - */ - public function compareKeys($a, $b) - { - return strcoll(Horde_String::lower($a, true, 'UTF-8'), Horde_String::lower($b, true, 'UTF-8')); - } - - /** - * Compare, in reverse order, array keys case insensitively for uksort. - * - * @param scalar $a TODO - * @param scalar $b TODO - * - * @return TODO - */ - public function reverseCompareKeys($a, $b) - { - return strcoll(Horde_String::lower($b, true, 'UTF-8'), Horde_String::lower($a, true, 'UTF-8')); - } - -} diff --git a/lib/horde/framework/Horde/Crypt/Blowfish.php b/lib/horde/framework/Horde/Crypt/Blowfish.php deleted file mode 100644 index 5587a3303d9..00000000000 --- a/lib/horde/framework/Horde/Crypt/Blowfish.php +++ /dev/null @@ -1,178 +0,0 @@ - - * Copyright 2012-2017 Horde LLC (http://www.horde.org/) - * - * See the enclosed file LICENSE for license information (LGPL). If you - * did not receive this file, see http://www.horde.org/licenses/lgpl21. - * - * @author Matthew Fonda - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ - -/** - * Provides blowfish encryption/decryption, with or without a secret key, - * for PHP strings. - * - * @author Matthew Fonda - * @author Michael Slusarz - * @category Horde - * @copyright 2005-2008 Matthew Fonda - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - * - * @property string $cipher The cipher block mode ('ecb' or 'cbc'). - * @property string $key The encryption key in use. - * @property mixed $iv The initialization vector (false if using 'ecb'). - */ -class Horde_Crypt_Blowfish -{ - // Constants for 'ignore' parameter of constructor. - const IGNORE_OPENSSL = 1; - const IGNORE_MCRYPT = 2; - - // Block size for Blowfish - const BLOCKSIZE = 8; - - // Maximum key size for Blowfish - const MAXKEYSIZE = 56; - - // IV Length for CBC - const IV_LENGTH = 8; - - /** - * Blowfish crypt driver. - * - * @var Horde_Crypt_Blowfish_Base - */ - protected $_crypt; - - /** - * Constructor. - * - * @param string $key Encryption key. - * @param array $opts Additional options: - * - cipher: (string) Either 'ecb' or 'cbc'. - * - ignore: (integer) A mask of drivers to ignore (IGNORE_* constants). - * - iv: (string) IV to use. - */ - public function __construct($key, array $opts = array()) - { - $opts = array_merge(array( - 'cipher' => 'ecb', - 'ignore' => 0, - 'iv' => null - ), $opts); - - if (!($opts['ignore'] & self::IGNORE_OPENSSL) && - Horde_Crypt_Blowfish_Openssl::supported()) { - $this->_crypt = new Horde_Crypt_Blowfish_Openssl($opts['cipher']); - } elseif (!($opts['ignore'] & self::IGNORE_MCRYPT) && - Horde_Crypt_Blowfish_Mcrypt::supported()) { - $this->_crypt = new Horde_Crypt_Blowfish_Mcrypt($opts['cipher']); - } else { - $this->_crypt = new Horde_Crypt_Blowfish_Php($opts['cipher']); - } - - $this->setKey($key, $opts['iv']); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'cipher': - case 'key': - case 'iv': - return $this->_crypt->$name; - } - } - - /** - * Encrypts a string. - * - * @param string $text The string to encrypt. - * - * @return string The ciphertext. - * @throws Horde_Crypt_Blowfish_Exception - */ - public function encrypt($text) - { - if (!is_string($text)) { - throw new Horde_Crypt_Blowfish_Exception('Data to encrypt must be a string.'); - } - - return $this->_crypt->encrypt($text); - } - - /** - * Decrypts a string. - * - * @param string $text The string to decrypt. - * - * @return string The plaintext. - * @throws Horde_Crypt_Blowfish_Exception - */ - public function decrypt($text) - { - if (!is_string($text)) { - throw new Horde_Crypt_Blowfish_Exception('Data to decrypt must be a string.'); - } - - return $this->_crypt->decrypt($text); - } - - /** - * Sets the secret key. - * - * The key must be non-zero, and less than or equal to MAXKEYSIZE - * characters (bytes) in length. - * - * @param string $key Key must be non-empty and less than MAXKEYSIZE - * bytes in length. - * @param string $iv The initialization vector to use. Only needed for - * 'cbc' cipher. If null, an IV is automatically - * generated. - * - * @throws Horde_Crypt_Blowfish_Exception - */ - public function setKey($key, $iv = null) - { - if (!is_string($key)) { - throw new Horde_Crypt_Blowfish_Exception('Encryption key must be a string.'); - } - - $len = strlen($key); - if (($len > self::MAXKEYSIZE) || ($len == 0)) { - throw new Horde_Crypt_Blowfish_Exception(sprintf('Encryption key must be less than %d characters (bytes) and non-zero. Supplied key length: %d', self::MAXKEYSIZE, $len)); - } - - $this->_crypt->key = $key; - - switch ($this->_crypt->cipher) { - case 'cbc': - if (is_null($iv)) { - if (is_null($this->iv)) { - $this->_crypt->setIv(); - } - } else { - $iv = substr($iv, 0, self::IV_LENGTH); - if (($len = strlen($iv)) < self::IV_LENGTH) { - $iv .= str_repeat(chr(0), self::IV_LENGTH - $len); - } - $this->_crypt->setIv($iv); - } - break; - - case 'ecb': - $this->iv = false; - break; - } - } - -} diff --git a/lib/horde/framework/Horde/Crypt/Blowfish/Base.php b/lib/horde/framework/Horde/Crypt/Blowfish/Base.php deleted file mode 100644 index b2c15581947..00000000000 --- a/lib/horde/framework/Horde/Crypt/Blowfish/Base.php +++ /dev/null @@ -1,128 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ - -/** - * Abstract base driver class for blowfish encryption. - * - * @author Michael Slusarz - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ -abstract class Horde_Crypt_Blowfish_Base -{ - /** - * Cipher method. - * - * @var string - */ - public $cipher; - - /** - * Initialization vector. - * - * @var string - */ - public $iv = null; - - /** - * Encryption key. - * - * @var string - */ - public $key; - - /** - * Is this driver supported on this system? - * - * @return boolean True if supported. - */ - public static function supported() - { - return true; - } - - /** - * Constructor. - * - * @param string $cipher Either 'ecb' or 'cbc'. - */ - public function __construct($cipher) - { - $this->cipher = $cipher; - } - - /** - * Encrypts a string. - * - * @param string $text The string to encrypt. - * - * @return string The ciphertext. - * @throws Horde_Crypt_Blowfish_Exception - */ - abstract public function encrypt($text); - - /** - * Decrypts a string. - * - * @param string $text The string to encrypt. - * - * @return string The ciphertext. - * @throws Horde_Crypt_Blowfish_Exception - */ - abstract public function decrypt($text); - - /** - * Sets the initialization vector (required for CBC mode). - * - * @param string $iv Initialization vector. - */ - public function setIv($iv = null) - { - $this->iv = is_null($iv) - ? substr(new Horde_Support_Randomid(), 0, 8) - : $iv; - } - - /** - * Pad text to match blocksize length. - * - * @param string $text Unpadded text. - * @param boolean $ignore Don't pad if already at blocksize length. - * - * @return string Padded text. - */ - protected function _pad($text, $ignore = false) - { - $blocksize = Horde_Crypt_Blowfish::BLOCKSIZE; - $padding = $blocksize - (strlen($text) % $blocksize); - - return ($ignore && ($padding == $blocksize)) - ? $text - : $text . str_repeat(chr($padding), $padding); - } - - /** - * Unpad text from blocksize boundary. - * - * @param string $text Padded text. - * - * @return string Unpadded text. - */ - protected function _unpad($text) - { - return substr($text, 0, ord(substr($text, -1)) * -1); - } - -} diff --git a/lib/horde/framework/Horde/Crypt/Blowfish/Exception.php b/lib/horde/framework/Horde/Crypt/Blowfish/Exception.php deleted file mode 100644 index 12054053e43..00000000000 --- a/lib/horde/framework/Horde/Crypt/Blowfish/Exception.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ - -/** - * Exception object for the Horde_Crypt_Blowfish package. - * - * @author Michael Slusarz - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ -class Horde_Crypt_Blowfish_Exception extends Horde_Exception_Wrapped -{ -} diff --git a/lib/horde/framework/Horde/Crypt/Blowfish/Mcrypt.php b/lib/horde/framework/Horde/Crypt/Blowfish/Mcrypt.php deleted file mode 100644 index c4f405c44d0..00000000000 --- a/lib/horde/framework/Horde/Crypt/Blowfish/Mcrypt.php +++ /dev/null @@ -1,87 +0,0 @@ - - * Copyright 2008 Philippe Jausions - * Copyright 2012-2017 Horde LLC (http://www.horde.org/) - * - * See the enclosed file LICENSE for license information (LGPL). If you - * did not receive this file, see http://www.horde.org/licenses/lgpl21. - * - * @author Matthew Fonda - * @author Philippe Jausions - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ - -/** - * Mcrypt driver for blowfish encryption. - * - * @author Matthew Fonda - * @author Philippe Jausions - * @author Michael Slusarz - * @category Horde - * @copyright 2005-2008 Matthew Fonda - * @copyright 2008 Philippe Jausions - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ -class Horde_Crypt_Blowfish_Mcrypt extends Horde_Crypt_Blowfish_Base -{ - /** - * Mcrypt resource. - * - * @var resource - */ - private $_mcrypt; - - /** - */ - public static function supported() - { - return PHP_VERSION_ID < 70100 && extension_loaded('mcrypt'); - } - - /** - */ - public function __construct($cipher) - { - parent::__construct($cipher); - - $this->_mcrypt = mcrypt_module_open(MCRYPT_BLOWFISH, '', $cipher, ''); - } - - /** - */ - public function encrypt($text) - { - mcrypt_generic_init($this->_mcrypt, $this->key, empty($this->iv) ? str_repeat('0', Horde_Crypt_Blowfish::IV_LENGTH) : $this->iv); - $out = mcrypt_generic($this->_mcrypt, $this->_pad($text)); - mcrypt_generic_deinit($this->_mcrypt); - - return $out; - } - - /** - */ - public function decrypt($text) - { - mcrypt_generic_init($this->_mcrypt, $this->key, empty($this->iv) ? str_repeat('0', Horde_Crypt_Blowfish::IV_LENGTH) : $this->iv); - $out = mdecrypt_generic($this->_mcrypt, $this->_pad($text, true)); - mcrypt_generic_deinit($this->_mcrypt); - - return $this->_unpad($out); - } - - /** - */ - public function setIv($iv = null) - { - $this->iv = is_null($iv) - ? mcrypt_create_iv(Horde_Crypt_Blowfish::IV_LENGTH, MCRYPT_RAND) - : $iv; - } - -} diff --git a/lib/horde/framework/Horde/Crypt/Blowfish/Openssl.php b/lib/horde/framework/Horde/Crypt/Blowfish/Openssl.php deleted file mode 100644 index c799932f495..00000000000 --- a/lib/horde/framework/Horde/Crypt/Blowfish/Openssl.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ - -/** - * Openssl driver for blowfish encryption. - * - * @author Michael Slusarz - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ -class Horde_Crypt_Blowfish_Openssl extends Horde_Crypt_Blowfish_Base -{ - /** - */ - public static function supported() - { - if (extension_loaded('openssl')) { - $ciphers = openssl_get_cipher_methods(); - return in_array('bf-ecb', $ciphers) && in_array('bf-cbc', $ciphers); - } - - return false; - } - - /** - */ - public function encrypt($text) - { - if (PHP_VERSION_ID <= 50302) { - return @openssl_encrypt($text, 'bf-' . $this->cipher, $this->key, true); - } elseif (PHP_VERSION_ID == 50303) { - // Need to mask error output, since an invalid warning message was - // issued prior to 5.3.4 for empty IVs in ECB mode. - return @openssl_encrypt($text, 'bf-' . $this->cipher, $this->key, true, strval($this->iv)); - } - - return openssl_encrypt($text, 'bf-' . $this->cipher, $this->key, true, strval($this->iv)); - } - - /** - */ - public function decrypt($text) - { - return (PHP_VERSION_ID <= 50302) - ? openssl_decrypt($text, 'bf-' . $this->cipher, $this->key, true) - : openssl_decrypt($text, 'bf-' . $this->cipher, $this->key, true, strval($this->iv)); - } - -} diff --git a/lib/horde/framework/Horde/Crypt/Blowfish/Pbkdf2.php b/lib/horde/framework/Horde/Crypt/Blowfish/Pbkdf2.php deleted file mode 100644 index 7db4f0a96b4..00000000000 --- a/lib/horde/framework/Horde/Crypt/Blowfish/Pbkdf2.php +++ /dev/null @@ -1,128 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ - -/** - * PBKDF2 (Password-Based Key Derivation Function 2) implementation (RFC - * 2898; PKCS #5 v2.0). - * - * @author Michael Slusarz - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - * @link https://defuse.ca/php-pbkdf2.htm pbkdf2 code released to the - * public domain. - */ -class Horde_Crypt_Blowfish_Pbkdf2 -{ - /** - * Hash algorithm used to create key. - * - * @var string - */ - public $hashAlgo; - - /** - * Number of iterations to use. - * - * @var integer - */ - public $iterations; - - /** - * Salt. - * - * @var string - */ - public $salt; - - /** - * The derived key. - * - * @var string - */ - protected $_key; - - /** - * Constructor. - * - * @param string $pass The password. - * @param string $key_length Length of the derived key (in bytes). - * @param array $opts Additional options: - * - algo: (string) Hash algorithm. - * - i_count: (integer) Iteration count. - * - salt: (string) The salt to use. - */ - public function __construct($pass, $key_length, array $opts = array()) - { - $this->iterations = isset($opts['i_count']) - ? $opts['i_count'] - : 16384; - - if (($key_length <= 0) || ($this->iterations <= 0)) { - throw new InvalidArgumentException('Invalid arguments'); - } - - $this->hashAlgo = isset($opts['algo']) - ? $opts['algo'] - : 'SHA256'; - - /* Nice to have, but salt does not need to be cryptographically - * secure random value. */ - $this->salt = isset($opts['salt']) - ? $opts['salt'] - : (function_exists('openssl_random_pseudo_bytes') - ? openssl_random_pseudo_bytes($key_length) - : substr(hash('sha512', new Horde_Support_Randomid(), true), 0, $key_length)); - - if (function_exists('hash_pbkdf2')) { - $this->_key = hash_pbkdf2( - $this->hashAlgo, - $pass, - $this->salt, - $this->iterations, - $key_length, - true - ); - return; - } - - $hash_length = strlen(hash($this->hashAlgo, '', true)); - $block_count = ceil($key_length / $hash_length); - - $hash = ''; - for ($i = 1; $i <= $block_count; ++$i) { - // $i encoded as 4 bytes, big endian. - $last = $this->salt . pack('N', $i); - for ($j = 0; $j < $this->iterations; $j++) { - $last = hash_hmac($this->hashAlgo, $last, $pass, true); - if ($j) { - $xorsum ^= $last; - } else { - $xorsum = $last; - } - } - $hash .= $xorsum; - } - - $this->_key = substr($hash, 0, $key_length); - } - - /** - */ - public function __toString() - { - return $this->_key; - } - -} diff --git a/lib/horde/framework/Horde/Crypt/Blowfish/Php.php b/lib/horde/framework/Horde/Crypt/Blowfish/Php.php deleted file mode 100644 index 2d10c7b1aa0..00000000000 --- a/lib/horde/framework/Horde/Crypt/Blowfish/Php.php +++ /dev/null @@ -1,75 +0,0 @@ - - * Copyright 2008 Philippe Jausions - * Copyright 2012-2017 Horde LLC (http://www.horde.org/) - * - * See the enclosed file LICENSE for license information (LGPL). If you - * did not receive this file, see http://www.horde.org/licenses/lgpl21. - * - * @author Matthew Fonda - * @author Philippe Jausions - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ - -/** - * Native PHP driver for blowfish encryption. - * - * @author Matthew Fonda - * @author Philippe Jausions - * @author Michael Slusarz - * @category Horde - * @copyright 2005-2008 Matthew Fonda - * @copyright 2008 Philippe Jausions - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ -class Horde_Crypt_Blowfish_Php extends Horde_Crypt_Blowfish_Base -{ - /** - * Subclass object. - * - * @var Horde_Crypt_Blowfish_Php_Base - */ - protected $_ob; - - /** - */ - public function encrypt($text) - { - $this->_init(); - return $this->_ob->encrypt($this->_pad($text), $this->iv); - } - - /** - */ - public function decrypt($text) - { - $this->_init(); - return $this->_unpad($this->_ob->decrypt($this->_pad($text, true), $this->iv)); - } - - /** - * Initialize the subclass. - */ - protected function _init() - { - if (!isset($this->_ob) || - ($this->_ob->md5 != hash('md5', $this->key))) { - switch ($this->cipher) { - case 'cbc': - $this->_ob = new Horde_Crypt_Blowfish_Php_Cbc($this->key); - break; - - case 'ecb': - $this->_ob = new Horde_Crypt_Blowfish_Php_Ecb($this->key); - break; - } - } - } - -} diff --git a/lib/horde/framework/Horde/Crypt/Blowfish/Php/Base.php b/lib/horde/framework/Horde/Crypt/Blowfish/Php/Base.php deleted file mode 100644 index 3ee9235cd47..00000000000 --- a/lib/horde/framework/Horde/Crypt/Blowfish/Php/Base.php +++ /dev/null @@ -1,459 +0,0 @@ - - * Copyright 2012-2017 Horde LLC (http://www.horde.org/) - * - * See the enclosed file LICENSE for license information (LGPL). If you - * did not receive this file, see http://www.horde.org/licenses/lgpl21. - * - * @author Matthew Fonda - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ - -/** - * Base subclass for the PHP driver. - * - * @author Matthew Fonda - * @author Michael Slusarz - * @category Horde - * @copyright 2005-2008 Matthew Fonda - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ -abstract class Horde_Crypt_Blowfish_Php_Base -{ - /** - * MD5 sum of the key used. - * - * @var string - */ - public $md5; - - /** - * P-Array contains 18 32-bit subkeys. - * - * @var array - */ - protected $_P = array( - 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, - 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89, - 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, - 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, - 0x9216D5D9, 0x8979FB1B - ); - - /** - * Array of four S-Blocks each containing 256 32-bit entries. - * - * @var array - */ - protected $_S = array( - array( - 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, - 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, - 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, - 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, - 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, - 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, - 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, - 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, - 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, - 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, - 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, - 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, - 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, - 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, - 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, - 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, - 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, - 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, - 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, - 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, - 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, - 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, - 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, - 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, - 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, - 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, - 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, - 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, - 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, - 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, - 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, - 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, - 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, - 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, - 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, - 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, - 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, - 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, - 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, - 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, - 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, - 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, - 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, - 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, - 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, - 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, - 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, - 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, - 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, - 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, - 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, - 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, - 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, - 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, - 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, - 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, - 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, - 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, - 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, - 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, - 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, - 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, - 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, - 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A - ), array( - 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, - 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, - 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, - 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, - 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, - 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, - 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, - 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, - 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, - 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, - 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, - 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, - 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, - 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, - 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, - 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, - 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, - 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, - 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, - 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, - 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, - 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, - 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, - 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, - 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, - 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, - 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, - 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, - 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, - 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, - 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, - 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, - 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, - 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, - 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, - 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, - 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, - 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, - 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, - 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, - 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, - 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, - 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, - 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, - 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, - 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, - 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, - 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, - 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, - 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, - 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, - 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, - 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, - 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, - 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, - 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, - 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, - 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, - 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, - 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, - 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, - 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, - 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, - 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 - ), array( - 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, - 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, - 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, - 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, - 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, - 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, - 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, - 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, - 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, - 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, - 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, - 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, - 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, - 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, - 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, - 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, - 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, - 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, - 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, - 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, - 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, - 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, - 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, - 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, - 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, - 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, - 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, - 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, - 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, - 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, - 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, - 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, - 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, - 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, - 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, - 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, - 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, - 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, - 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, - 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, - 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, - 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, - 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, - 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, - 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, - 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, - 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, - 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, - 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, - 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, - 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, - 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, - 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, - 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, - 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, - 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, - 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, - 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, - 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, - 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, - 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, - 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, - 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, - 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 - ), array( - 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, - 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, - 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, - 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, - 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, - 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, - 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, - 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, - 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, - 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, - 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, - 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, - 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, - 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, - 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, - 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, - 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, - 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, - 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, - 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, - 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, - 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, - 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, - 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, - 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, - 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, - 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, - 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, - 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, - 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, - 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, - 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, - 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, - 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, - 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, - 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, - 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, - 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, - 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, - 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, - 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, - 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, - 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, - 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, - 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, - 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, - 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, - 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, - 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, - 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, - 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, - 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, - 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, - 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, - 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, - 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, - 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, - 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, - 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, - 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, - 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, - 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, - 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, - 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 - ) - ); - - /** - * Constructor. - * - * @param string $key Encrpytion key. - */ - public function __construct($key) - { - $data = $datal = $datar = $k = 0; - $len = strlen($key); - - for ($i = 0; $i < 18; ++$i) { - $data = 0; - for ($j = 4; $j > 0; --$j) { - $data = $data << 8 | ord($key[$k]); - $k = ($k + 1) % $len; - } - $this->_P[$i] ^= $data; - } - - for ($i = 0; $i <= 16; $i += 2) { - $this->_encipher($datal, $datar); - $this->_P[$i] = $datal; - $this->_P[$i+1] = $datar; - } - - for ($i = 0; $i < 256; $i += 2) { - $this->_encipher($datal, $datar); - $this->_S[0][$i] = $datal; - $this->_S[0][$i+1] = $datar; - } - - for ($i = 0; $i < 256; $i += 2) { - $this->_encipher($datal, $datar); - $this->_S[1][$i] = $datal; - $this->_S[1][$i+1] = $datar; - } - - for ($i = 0; $i < 256; $i += 2) { - $this->_encipher($datal, $datar); - $this->_S[2][$i] = $datal; - $this->_S[2][$i+1] = $datar; - } - - for ($i = 0; $i < 256; $i += 2) { - $this->_encipher($datal, $datar); - $this->_S[3][$i] = $datal; - $this->_S[3][$i+1] = $datar; - } - - $this->md5 = hash('md5', $key); - } - - /** - */ - abstract public function encrypt($text, $iv); - - /** - */ - abstract public function decrypt($text, $iv); - - /** - * Workaround for XOR on certain systems. - * - * @param integer|float $l - * @param integer|float $r - * - * @return float - */ - protected function _binxor($l, $r) - { - $x = (($l < 0) ? (float)($l + 4294967296) : (float)$l) - ^ (($r < 0) ? (float)($r + 4294967296) : (float)$r); - - return (float)(($x < 0) ? $x + 4294967296 : $x); - } - - /** - * Enciphers a single 64-bit block. - * - * @param int &$Xl - * @param int &$Xr - */ - protected function _encipher(&$Xl, &$Xr) - { - if ($Xl < 0) { - $Xl += 4294967296; - } - - if ($Xr < 0) { - $Xr += 4294967296; - } - - for ($i = 0; $i < 16; ++$i) { - $temp = $Xl ^ $this->_P[$i]; - if ($temp < 0) { - $temp += 4294967296; - } - - $Xl = fmod((fmod($this->_S[0][($temp >> 24) & 255] - + $this->_S[1][($temp >> 16) & 255], 4294967296) - ^ $this->_S[2][($temp >> 8) & 255]) - + $this->_S[3][$temp & 255], 4294967296) ^ $Xr; - $Xr = $temp; - } - - $Xr = $this->_binxor($Xl, $this->_P[16]); - $Xl = $this->_binxor($temp, $this->_P[17]); - } - - /** - * Deciphers a single 64-bit block. - * - * @param int &$Xl - * @param int &$Xr - */ - protected function _decipher(&$Xl, &$Xr) - { - if ($Xl < 0) { - $Xl += 4294967296; - } - if ($Xr < 0) { - $Xr += 4294967296; - } - - for ($i = 17; $i > 1; --$i) { - $temp = $Xl ^ $this->_P[$i]; - if ($temp < 0) { - $temp += 4294967296; - } - - $Xl = fmod((fmod($this->_S[0][($temp >> 24) & 255] - + $this->_S[1][($temp >> 16) & 255], 4294967296) - ^ $this->_S[2][($temp >> 8) & 255]) - + $this->_S[3][$temp & 255], 4294967296) ^ $Xr; - $Xr = $temp; - } - - $Xr = $this->_binxor($Xl, $this->_P[1]); - $Xl = $this->_binxor($temp, $this->_P[0]); - } - -} diff --git a/lib/horde/framework/Horde/Crypt/Blowfish/Php/Cbc.php b/lib/horde/framework/Horde/Crypt/Blowfish/Php/Cbc.php deleted file mode 100644 index d0cb5a6277c..00000000000 --- a/lib/horde/framework/Horde/Crypt/Blowfish/Php/Cbc.php +++ /dev/null @@ -1,73 +0,0 @@ - - * Copyright 2008 Philippe Jausions - * Copyright 2012-2017 Horde LLC (http://www.horde.org/) - * - * See the enclosed file LICENSE for license information (LGPL). If you - * did not receive this file, see http://www.horde.org/licenses/lgpl21. - * - * @author Matthew Fonda - * @author Philippe Jausions - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ - -/** - * PHP implementation of the Blowfish algorithm in CBC mode. - * - * @author Matthew Fonda - * @author Philippe Jausions - * @author Michael Slusarz - * @category Horde - * @copyright 2005-2008 Matthew Fonda - * @copyright 2008 Philippe Jausions - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ -class Horde_Crypt_Blowfish_Php_Cbc extends Horde_Crypt_Blowfish_Php_Base -{ - /** - */ - public function encrypt($text, $iv) - { - $cipherText = ''; - $len = strlen($text); - - list(, $Xl, $Xr) = unpack('N2', substr($text, 0, 8) ^ $iv); - $this->_encipher($Xl, $Xr); - $cipherText .= pack('N2', $Xl, $Xr); - - for ($i = 8; $i < $len; $i += 8) { - list(, $Xl, $Xr) = unpack('N2', substr($text, $i, 8) ^ substr($cipherText, $i - 8, 8)); - $this->_encipher($Xl, $Xr); - $cipherText .= pack('N2', $Xl, $Xr); - } - - return $cipherText; - } - - /** - */ - public function decrypt($text, $iv) - { - $plainText = ''; - $len = strlen($text); - - list(, $Xl, $Xr) = unpack('N2', substr($text, 0, 8)); - $this->_decipher($Xl, $Xr); - $plainText .= (pack('N2', $Xl, $Xr) ^ $iv); - - for ($i = 8; $i < $len; $i += 8) { - list(, $Xl, $Xr) = unpack('N2', substr($text, $i, 8)); - $this->_decipher($Xl, $Xr); - $plainText .= (pack('N2', $Xl, $Xr) ^ substr($text, $i - 8, 8)); - } - - return $plainText; - } - -} diff --git a/lib/horde/framework/Horde/Crypt/Blowfish/Php/Ecb.php b/lib/horde/framework/Horde/Crypt/Blowfish/Php/Ecb.php deleted file mode 100644 index 89c252b34a1..00000000000 --- a/lib/horde/framework/Horde/Crypt/Blowfish/Php/Ecb.php +++ /dev/null @@ -1,65 +0,0 @@ - - * Copyright 2008 Philippe Jausions - * Copyright 2012-2017 Horde LLC (http://www.horde.org/) - * - * See the enclosed file LICENSE for license information (LGPL). If you - * did not receive this file, see http://www.horde.org/licenses/lgpl21. - * - * @author Matthew Fonda - * @author Philippe Jausions - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ - -/** - * PHP implementation of the Blowfish algorithm in ECB mode. - * - * @author Matthew Fonda - * @author Philippe Jausions - * @author Michael Slusarz - * @category Horde - * @copyright 2005-2008 Matthew Fonda - * @copyright 2008 Philippe Jausions - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Crypt_Blowfish - */ -class Horde_Crypt_Blowfish_Php_Ecb extends Horde_Crypt_Blowfish_Php_Base -{ - /** - */ - public function encrypt($text, $iv) - { - $cipherText = ''; - $len = strlen($text); - - for ($i = 0; $i < $len; $i += 8) { - list(, $Xl, $Xr) = unpack('N2', substr($text, $i, 8)); - $this->_encipher($Xl, $Xr); - $cipherText .= pack('N2', $Xl, $Xr); - } - - return $cipherText; - } - - /** - */ - public function decrypt($text, $iv) - { - $plainText = ''; - $len = strlen($text); - - for ($i = 0; $i < $len; $i += 8) { - list(, $Xl, $Xr) = unpack('N2', substr($text, $i, 8)); - $this->_decipher($Xl, $Xr); - $plainText .= pack('N2', $Xl, $Xr); - } - - return $plainText; - } - -} diff --git a/lib/horde/framework/Horde/Domhtml.php b/lib/horde/framework/Horde/Domhtml.php deleted file mode 100644 index 234c4dd804b..00000000000 --- a/lib/horde/framework/Horde/Domhtml.php +++ /dev/null @@ -1,341 +0,0 @@ - - * @category Horde - * @copyright 2010-2017 Horde LLC - * @package Util - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - */ -class Horde_Domhtml implements Iterator -{ - /** - * DOM object. - * - * @var DOMDocument - */ - public $dom; - - /** - * Iterator status. - * - * @var array - */ - protected $_iterator = null; - - /** - * Original charset of data. - * - * @var string - */ - protected $_origCharset; - - /** - * Encoding tag added to beginning of output. - * - * @var string - */ - protected $_xmlencoding = ''; - - /** - * Constructor. - * - * @param string $text The text of the HTML document. - * @param string $charset The charset of the HTML document. - * - * @throws Exception - */ - public function __construct($text, $charset = null) - { - if (!extension_loaded('dom')) { - throw new Exception('DOM extension is not available.'); - } - - // Bug #9616: Make sure we have valid HTML input. - if (!strlen($text)) { - $text = ''; - } - - $old_error = libxml_use_internal_errors(true); - $this->dom = new DOMDocument(); - - if (is_null($charset)) { - /* If no charset given, charset is whatever libxml tells us the - * encoding should be defaulting to 'iso-8859-1'. */ - $this->_loadHTML($text); - $this->_origCharset = $this->dom->encoding - ? $this->dom->encoding - : 'iso-8859-1'; - } else { - /* Convert/try with UTF-8 first. */ - $this->_origCharset = Horde_String::lower($charset); - $this->_xmlencoding = ''; - $this->_loadHTML( - $this->_xmlencoding . Horde_String::convertCharset($text, $charset, 'UTF-8') - ); - - if ($this->dom->encoding && - (Horde_String::lower($this->dom->encoding) != 'utf-8')) { - /* Convert charset to what the HTML document says it SHOULD - * be. */ - $this->_loadHTML( - Horde_String::convertCharset($text, $charset, $this->dom->encoding) - ); - $this->_xmlencoding = ''; - } - } - - if ($old_error) { - libxml_use_internal_errors(false); - } - - /* Sanity checking: make sure we have the documentElement object. */ - if (!$this->dom->documentElement) { - $this->dom->appendChild($this->dom->createElement('html')); - } - - /* Remove old charset information. */ - $xpath = new DOMXPath($this->dom); - $domlist = $xpath->query('/html/head/meta[@http-equiv="content-type"]'); - for ($i = $domlist->length; $i > 0; --$i) { - $meta = $domlist->item($i - 1); - $meta->parentNode->removeChild($meta); - } - } - - /** - * Returns the HEAD element, or creates one if it doesn't exist. - * - * @return DOMElement HEAD element. - */ - public function getHead() - { - $head = $this->dom->getElementsByTagName('head'); - if ($head->length) { - return $head->item(0); - } - - $headelt = $this->dom->createElement('head'); - $this->dom->documentElement->insertBefore($headelt, $this->dom->documentElement->firstChild); - - return $headelt; - } - - /** - * Returns the BODY element, or creates one if it doesn't exist. - * - * @since 2.2.0 - * - * @return DOMElement BODY element. - */ - public function getBody() - { - $body = $this->dom->getElementsByTagName('body'); - if ($body->length) { - return $body->item(0); - } - - $bodyelt = $this->dom->createElement('body'); - $this->dom->documentElement->appendChild($bodyelt); - - return $bodyelt; - } - - /** - * Returns the full HTML text in the original charset. - * - * @param array $opts Additional options: (since 2.1.0) - * - charset: (string) Return using this charset. If set but empty, will - * return as currently stored in the DOM object. - * - metacharset: (boolean) If true, will add a META tag containing the - * charset information. - * - * @return string HTML text. - */ - public function returnHtml(array $opts = array()) - { - $curr_charset = $this->getCharset(); - if (strcasecmp($curr_charset, 'US-ASCII') === 0) { - $curr_charset = 'UTF-8'; - } - $charset = array_key_exists('charset', $opts) - ? (empty($opts['charset']) ? $curr_charset : $opts['charset']) - : $this->_origCharset; - - if (empty($opts['metacharset'])) { - $text = $this->dom->saveHTML(); - } else { - /* Add placeholder for META tag. Can't add charset yet because DOM - * extension will alter output if it exists. */ - $meta = $this->dom->createElement('meta'); - $meta->setAttribute('http-equiv', 'content-type'); - $meta->setAttribute('horde_dom_html_charset', ''); - - $head = $this->getHead(); - $head->insertBefore($meta, $head->firstChild); - - $text = str_replace( - 'horde_dom_html_charset=""', - 'content="text/html; charset=' . $charset . '"', - $this->dom->saveHTML() - ); - - $head->removeChild($meta); - } - - if (strcasecmp($curr_charset, $charset) !== 0) { - $text = Horde_String::convertCharset($text, $curr_charset, $charset); - } - - if (!$this->_xmlencoding || - (($pos = strpos($text, $this->_xmlencoding)) === false)) { - return $text; - } - - return substr_replace($text, '', $pos, strlen($this->_xmlencoding)); - } - - /** - * Returns the body text in the original charset. - * - * @return string HTML text. - */ - public function returnBody() - { - $body = $this->getBody(); - $text = ''; - - if ($body->hasChildNodes()) { - foreach ($body->childNodes as $child) { - $text .= $this->dom->saveXML($child); - } - } - - return Horde_String::convertCharset($text, 'UTF-8', $this->_origCharset); - } - - /** - * Get the charset of the DOM data. - * - * @since 2.1.0 - * - * @return string Charset of DOM data. - */ - public function getCharset() - { - return $this->dom->encoding - ? $this->dom->encoding - : ($this->_xmlencoding ? 'UTF-8' : $this->_origCharset); - } - - /** - * Loads the HTML data. - * - * @param string $html HTML data. - */ - protected function _loadHTML($html) - { - if (version_compare(PHP_VERSION, '5.4', '>=')) { - $mask = defined('LIBXML_PARSEHUGE') - ? LIBXML_PARSEHUGE - : 0; - $mask |= defined('LIBXML_COMPACT') - ? LIBXML_COMPACT - : 0; - $this->dom->loadHTML($html, $mask); - } else { - $this->dom->loadHTML($html); - } - } - - /* Iterator methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function current() - { - if ($this->_iterator instanceof DOMDocument) { - return $this->_iterator; - } - - $curr = end($this->_iterator); - return $curr['list']->item($curr['i']); - } - - /** - */ - #[ReturnTypeWillChange] - public function key() - { - return 0; - } - - /** - */ - #[ReturnTypeWillChange] - public function next() - { - /* Iterate in the reverse direction through the node list. This allows - * alteration of the original list without breaking things (foreach() - * w/removeChild() may exit iteration after removal is complete. */ - - if ($this->_iterator instanceof DOMDocument) { - $this->_iterator = array(); - $curr = array(); - $node = $this->dom; - } elseif (empty($this->_iterator)) { - $this->_iterator = null; - return; - } else { - $curr = &$this->_iterator[count($this->_iterator) - 1]; - $node = $curr['list']->item($curr['i']); - } - - if (empty($curr['child']) && - ($node instanceof DOMNode) && - $node->hasChildNodes()) { - $curr['child'] = true; - $this->_iterator[] = array( - 'child' => false, - 'i' => $node->childNodes->length - 1, - 'list' => $node->childNodes - ); - } elseif (--$curr['i'] < 0) { - array_pop($this->_iterator); - $this->next(); - } else { - $curr['child'] = false; - } - } - - /** - */ - #[ReturnTypeWillChange] - public function rewind() - { - $this->_iterator = $this->dom; - } - - /** - */ - #[ReturnTypeWillChange] - public function valid() - { - return !is_null($this->_iterator); - } - -} diff --git a/lib/horde/framework/Horde/Exception.php b/lib/horde/framework/Horde/Exception.php deleted file mode 100644 index c39e7b3e496..00000000000 --- a/lib/horde/framework/Horde/Exception.php +++ /dev/null @@ -1,73 +0,0 @@ -_logLevel; - } - - /** - * Sets the log level. - * - * @param mixed $level The log level. - */ - public function setLogLevel($level = 0) - { - if (is_string($level)) { - $level = defined('Horde_Log::' . $level) - ? constant('Horde_Log::' . $level) - : 0; - } - - $this->_logLevel = $level; - } - -} diff --git a/lib/horde/framework/Horde/Exception/LastError.php b/lib/horde/framework/Horde/Exception/LastError.php deleted file mode 100644 index cbe79059326..00000000000 --- a/lib/horde/framework/Horde/Exception/LastError.php +++ /dev/null @@ -1,55 +0,0 @@ -file = $code_or_lasterror['file']; - $this->line = $code_or_lasterror['line']; - } else { - parent::__construct($message, $code_or_lasterror ?? 0); - } - } - -} diff --git a/lib/horde/framework/Horde/Exception/NotFound.php b/lib/horde/framework/Horde/Exception/NotFound.php deleted file mode 100644 index 917ce776ea4..00000000000 --- a/lib/horde/framework/Horde/Exception/NotFound.php +++ /dev/null @@ -1,41 +0,0 @@ -getMessage(), $error->getCode()); - $this->details = $this->_getPearTrace($error); - } - - /** - * Return a trace for the PEAR error. - * - * @param PEAR_Error $error The PEAR error. - * - * @return string The backtrace as a string. - */ - private function _getPearTrace(PEAR_Error $error) - { - $pear_error = ''; - $backtrace = $error->getBacktrace(); - if (!empty($backtrace)) { - $pear_error .= 'PEAR backtrace:' . "\n\n"; - foreach ($backtrace as $frame) { - $pear_error .= - (isset($frame['class']) ? $frame['class'] : '') - . (isset($frame['type']) ? $frame['type'] : '') - . (isset($frame['function']) ? $frame['function'] : 'unkown') . ' ' - . (isset($frame['file']) ? $frame['file'] : 'unkown') . ':' - . (isset($frame['line']) ? $frame['line'] : 'unkown') . "\n"; - } - } - $userinfo = $error->getUserInfo(); - if (!empty($userinfo)) { - $pear_error .= "\n" . 'PEAR user info:' . "\n\n"; - if (is_string($userinfo)) { - $pear_error .= $userinfo; - } else { - $pear_error .= print_r($userinfo, true); - } - } - return $pear_error; - } - - /** - * Exception handling. - * - * @param mixed $result The result to be checked for a PEAR_Error. - * - * @return mixed Returns the original result if it was no PEAR_Error. - * - * @throws Horde_Exception_Pear In case the result was a PEAR_Error. - */ - public static function catchError($result) - { - if ($result instanceof PEAR_Error) { - throw new self::$_class($result); - } - return $result; - } -} diff --git a/lib/horde/framework/Horde/Exception/PermissionDenied.php b/lib/horde/framework/Horde/Exception/PermissionDenied.php deleted file mode 100644 index 3edd25181d3..00000000000 --- a/lib/horde/framework/Horde/Exception/PermissionDenied.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL - * @package Exception - */ - -/** - * Horde_Exception_Translation is the translation wrapper class for Horde_Exception. - * - * @author Jan Schneider - * @category Horde - * @copyright 2010-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL - * @package Exception - */ -class Horde_Exception_Translation extends Horde_Translation_Autodetect -{ - /** - * The translation domain - * - * @var string - */ - protected static $_domain = 'Horde_Exception'; - - /** - * The absolute PEAR path to the translations for the default gettext handler. - * - * @var string - */ - protected static $_pearDirectory = '@data_dir@'; -} diff --git a/lib/horde/framework/Horde/Exception/Wrapped.php b/lib/horde/framework/Horde/Exception/Wrapped.php deleted file mode 100644 index b7d8e7280e8..00000000000 --- a/lib/horde/framework/Horde/Exception/Wrapped.php +++ /dev/null @@ -1,56 +0,0 @@ -getCode(); - } - if ($message instanceof Exception) { - $previous = $message; - } - if (method_exists($message, 'getUserinfo') && - $details = $message->getUserinfo()) { - $this->details = $details; - } elseif (!empty($message->details)) { - $this->details = $message->details; - } - $message = (string)$message->getMessage(); - } - - parent::__construct($message, $code, $previous); - } -} diff --git a/lib/horde/framework/Horde/Idna.php b/lib/horde/framework/Horde/Idna.php deleted file mode 100644 index f2ecbe81a8c..00000000000 --- a/lib/horde/framework/Horde/Idna.php +++ /dev/null @@ -1,178 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/bsd BSD - * @package Idna - */ - -/** - * Provide normalized encoding/decoding support for IDNA strings. - * - * @author Michael Slusarz - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd BSD - * @package Idna - */ -class Horde_Idna -{ - /** - * The backend to use. - * - * @var mixed - */ - protected static $_backend; - - /** - * @throws Horde_Idna_Exception - */ - public static function encode($data) - { - switch ($backend = static::_getBackend()) { - case 'INTL': - if ($data === null) { - return false; - } - return idn_to_ascii($data); - - case 'INTL_UTS46': - if ($data === null) { - return false; - } - $result = idn_to_ascii($data, 0, INTL_IDNA_VARIANT_UTS46, $info); - self::_checkForError($info); - return $result; - - default: - return $backend->encode($data); - } - } - - /** - * @throws Horde_Idna_Exception - */ - public static function decode($data) - { - switch ($backend = static::_getBackend()) { - case 'INTL': - case 'INTL_UTS46': - $parts = explode('.', $data); - foreach ($parts as &$part) { - if (strpos($part, 'xn--') === 0) { - switch ($backend) { - case 'INTL': - $part = idn_to_utf8($part); - break; - - case 'INTL_UTS46': - $part = idn_to_utf8($part, 0, INTL_IDNA_VARIANT_UTS46, $info); - self::_checkForError($info); - break; - } - } - } - return implode('.', $parts); - - default: - return $backend->decode($data); - } - } - - /** - * Checks if the $idna_info parameter of idn_to_ascii() or idn_to_utf8() - * contains errors. - * - * @param array $info Fourth parameter to idn_to_ascii() or idn_to_utf8(). - * - * @throws Horde_Idna_Exception - */ - protected static function _checkForError($info) - { - if (!isset($info['errors'])) { - return; - } - switch (true) { - case $info['errors'] & IDNA_ERROR_EMPTY_LABEL: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Domain name is empty" - )); - case $info['errors'] & IDNA_ERROR_LABEL_TOO_LONG: - case $info['errors'] & IDNA_ERROR_DOMAIN_NAME_TOO_LONG: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Domain name is too long" - )); - case $info['errors'] & IDNA_ERROR_LEADING_HYPHEN: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Starts with a hyphen" - )); - case $info['errors'] & IDNA_ERROR_TRAILING_HYPHEN: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Ends with a hyphen" - )); - case $info['errors'] & IDNA_ERROR_HYPHEN_3_4: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Contains hyphen in the third and fourth positions" - )); - case $info['errors'] & IDNA_ERROR_LEADING_COMBINING_MARK: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Starts with a combining mark" - )); - case $info['errors'] & IDNA_ERROR_DISALLOWED: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Contains disallowed characters" - )); - case $info['errors'] & IDNA_ERROR_PUNYCODE: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Starts with \"xn--\" but does not contain valid Punycode" - )); - case $info['errors'] & IDNA_ERROR_LABEL_HAS_DOT: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Contains a dot" - )); - case $info['errors'] & IDNA_ERROR_INVALID_ACE_LABEL: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "ACE label does not contain a valid label string" - )); - case $info['errors'] & IDNA_ERROR_BIDI: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Does not meet the IDNA BiDi requirements (for right-to-left characters)" - )); - case $info['errors'] & IDNA_ERROR_CONTEXTJ: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Does not meet the IDNA CONTEXTJ requirements" - )); - case $info['errors']: - throw new Horde_Idna_Exception(Horde_Idna_Translation::t( - "Unknown error" - )); - } - } - - /** - * Return the IDNA backend. - * - * @return mixed IDNA backend (false if none available). - */ - protected static function _getBackend() - { - if (!isset(self::$_backend)) { - if (extension_loaded('intl')) { - /* Only available in PHP > 5.4.0 */ - self::$_backend = defined('INTL_IDNA_VARIANT_UTS46') - ? 'INTL_UTS46' - : 'INTL'; - } else { - self::$_backend = new Horde_Idna_Punycode(); - } - } - - return self::$_backend; - } - -} diff --git a/lib/horde/framework/Horde/Idna/Exception.php b/lib/horde/framework/Horde/Idna/Exception.php deleted file mode 100644 index ce6612e7f74..00000000000 --- a/lib/horde/framework/Horde/Idna/Exception.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/bsd BSD - * @package Idna - */ - -/** - * Exception class for the Horde_Idna package. - * - * @author Michael Slusarz - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd BSD - * @package Idna - */ -class Horde_Idna_Exception extends Horde_Exception -{} diff --git a/lib/horde/framework/Horde/Idna/Punycode.php b/lib/horde/framework/Horde/Idna/Punycode.php deleted file mode 100644 index 3192f6a18d4..00000000000 --- a/lib/horde/framework/Horde/Idna/Punycode.php +++ /dev/null @@ -1,354 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/bsd BSD - * @package Idna - */ - -/** - * Punycode implementation as described in RFC 3492. - * - * Original code (v1.0.1; released under the MIT License): - * https://github.com/true/php-punycode/ - * - * @author Renan Gonçalves - * @author Michael Slusarz - * @category Horde - * @copyright 2014 TrueServer B.V. - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd BSD - * @package Idna - * @link http://tools.ietf.org/html/rfc3492 - */ -class Horde_Idna_Punycode -{ - /** - * Bootstring parameter values. - */ - const BASE = 36; - const TMIN = 1; - const TMAX = 26; - const SKEW = 38; - const DAMP = 700; - const INITIAL_BIAS = 72; - const INITIAL_N = 128; - const PREFIX = 'xn--'; - const DELIMITER = '-'; - - /** - * Encode table. - * - * @param array - */ - protected static $_encodeTable = array( - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', - 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', - 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - ); - - /** - * Decode table. - * - * @param array - */ - protected static $_decodeTable = array( - 'a' => 0, 'b' => 1, 'c' => 2, 'd' => 3, 'e' => 4, 'f' => 5, - 'g' => 6, 'h' => 7, 'i' => 8, 'j' => 9, 'k' => 10, 'l' => 11, - 'm' => 12, 'n' => 13, 'o' => 14, 'p' => 15, 'q' => 16, 'r' => 17, - 's' => 18, 't' => 19, 'u' => 20, 'v' => 21, 'w' => 22, 'x' => 23, - 'y' => 24, 'z' => 25, '0' => 26, '1' => 27, '2' => 28, '3' => 29, - '4' => 30, '5' => 31, '6' => 32, '7' => 33, '8' => 34, '9' => 35 - ); - - /** - * Encode a domain to its Punycode version. - * - * @param string $input Domain name in Unicde to be encoded. - * - * @return string Punycode representation in ASCII. - */ - public function encode($input) - { - $parts = explode('.', $input); - - foreach ($parts as &$part) { - $part = $this->_encodePart($part); - } - - return implode('.', $parts); - } - - /** - * Encode a part of a domain name, such as tld, to its Punycode version. - * - * @param string $input Part of a domain name. - * - * @return string Punycode representation of a domain part. - */ - protected function _encodePart($input) - { - $codePoints = $this->_codePoints($input); - - $n = static::INITIAL_N; - $bias = static::INITIAL_BIAS; - $delta = 0; - $h = $b = count($codePoints['basic']); - - $output = ''; - foreach ($codePoints['basic'] as $code) { - $output .= $this->_codePointToChar($code); - } - if ($input === $output) { - return $output; - } - if ($b > 0) { - $output .= static::DELIMITER; - } - - $codePoints['nonBasic'] = array_unique($codePoints['nonBasic']); - sort($codePoints['nonBasic']); - - $i = 0; - $length = Horde_String::length($input, 'UTF-8'); - - while ($h < $length) { - $m = $codePoints['nonBasic'][$i++]; - $delta = $delta + ($m - $n) * ($h + 1); - $n = $m; - - foreach ($codePoints['all'] as $c) { - if (($c < $n) || ($c < static::INITIAL_N)) { - ++$delta; - } - - if ($c === $n) { - $q = $delta; - for ($k = static::BASE; ; $k += static::BASE) { - $t = $this->_calculateThreshold($k, $bias); - if ($q < $t) { - break; - } - - $code = $t + (($q - $t) % (static::BASE - $t)); - $output .= static::$_encodeTable[$code]; - - $q = ($q - $t) / (static::BASE - $t); - } - - $output .= static::$_encodeTable[$q]; - $bias = $this->_adapt($delta, $h + 1, ($h === $b)); - $delta = 0; - ++$h; - } - } - - ++$delta; - ++$n; - } - - return static::PREFIX . $output; - } - - /** - * Decode a Punycode domain name to its Unicode counterpart. - * - * @param string $input Domain name in Punycode - * - * @return string Unicode domain name. - */ - public function decode($input) - { - $parts = explode('.', $input); - - foreach ($parts as &$part) { - if (strpos($part, static::PREFIX) === 0) { - $part = $this->_decodePart( - substr($part, strlen(static::PREFIX)) - ); - } - } - - return implode('.', $parts); - } - - /** - * Decode a part of domain name, such as tld. - * - * @param string $input Part of a domain name. - * - * @return string Unicode domain part. - */ - protected function _decodePart($input) - { - $n = static::INITIAL_N; - $i = 0; - $bias = static::INITIAL_BIAS; - $output = ''; - - $pos = strrpos($input, static::DELIMITER); - if ($pos !== false) { - $output = substr($input, 0, $pos++); - } else { - $pos = 0; - } - - $outputLength = strlen($output); - $inputLength = strlen($input); - - /* Punycode lookup is case-insensitive. */ - $input = Horde_String::lower($input); - - while ($pos < $inputLength) { - $oldi = $i; - $w = 1; - - for ($k = static::BASE; ; $k += static::BASE) { - $digit = static::$_decodeTable[$input[$pos++]]; - $i = $i + ($digit * $w); - $t = $this->_calculateThreshold($k, $bias); - - if ($digit < $t) { - break; - } - - $w = $w * (static::BASE - $t); - } - - $bias = $this->_adapt($i - $oldi, ++$outputLength, ($oldi === 0)); - $n = $n + (int) ($i / $outputLength); - $i = $i % ($outputLength); - - $output = Horde_String::substr($output, 0, $i, 'UTF-8') . - $this->_codePointToChar($n) . - Horde_String::substr($output, $i, $outputLength - 1, 'UTF-8'); - - ++$i; - } - - return $output; - } - - /** - * Calculate the bias threshold to fall between TMIN and TMAX. - * - * @param integer $k - * @param integer $bias - * - * @return integer - */ - protected function _calculateThreshold($k, $bias) - { - if ($k <= ($bias + static::TMIN)) { - return static::TMIN; - } elseif ($k >= ($bias + static::TMAX)) { - return static::TMAX; - } - return $k - $bias; - } - - /** - * Bias adaptation. - * - * @param integer $delta - * @param integer $numPoints - * @param boolean $firstTime - * - * @return integer - */ - protected function _adapt($delta, $numPoints, $firstTime) - { - $delta = (int) ( - ($firstTime) - ? $delta / static::DAMP - : $delta / 2 - ); - $delta += (int) ($delta / $numPoints); - - $k = 0; - while ($delta > ((static::BASE - static::TMIN) * static::TMAX) / 2) { - $delta = (int) ($delta / (static::BASE - static::TMIN)); - $k = $k + static::BASE; - } - $k = $k + (int) (((static::BASE - static::TMIN + 1) * $delta) / ($delta + static::SKEW)); - - return $k; - } - - /** - * List code points for a given input. - * - * @param string $input - * - * @return array Multi-dimension array with basic, non-basic and - * aggregated code points. - */ - protected function _codePoints($input) - { - $codePoints = array( - 'all' => array(), - 'basic' => array(), - 'nonBasic' => array() - ); - - $len = Horde_String::length($input, 'UTF-8'); - for ($i = 0; $i < $len; ++$i) { - $char = Horde_String::substr($input, $i, 1, 'UTF-8'); - $code = $this->_charToCodePoint($char); - if ($code < 128) { - $codePoints['all'][] = $codePoints['basic'][] = $code; - } else { - $codePoints['all'][] = $codePoints['nonBasic'][] = $code; - } - } - - return $codePoints; - } - - /** - * Convert a single or multi-byte character to its code point. - * - * @param string $char - * - * @return integer - */ - protected function _charToCodePoint($char) - { - $code = ord($char[0]); - if ($code < 128) { - return $code; - } elseif ($code < 224) { - return (($code - 192) * 64) + (ord($char[1]) - 128); - } elseif ($code < 240) { - return (($code - 224) * 4096) + ((ord($char[1]) - 128) * 64) + (ord($char[2]) - 128); - } - return (($code - 240) * 262144) + ((ord($char[1]) - 128) * 4096) + ((ord($char[2]) - 128) * 64) + (ord($char[3]) - 128); - } - - /** - * Convert a code point to its single or multi-byte character - * - * @param integer $code - * - * @return string - */ - protected function _codePointToChar($code) - { - if ($code <= 0x7F) { - return chr($code); - } elseif ($code <= 0x7FF) { - return chr(($code >> 6) + 192) . chr(($code & 63) + 128); - } elseif ($code <= 0xFFFF) { - return chr(($code >> 12) + 224) . chr((($code >> 6) & 63) + 128) . chr(($code & 63) + 128); - } - return chr(($code >> 18) + 240) . chr((($code >> 12) & 63) + 128) . chr((($code >> 6) & 63) + 128) . chr(($code & 63) + 128); - } - -} diff --git a/lib/horde/framework/Horde/Idna/Translation.php b/lib/horde/framework/Horde/Idna/Translation.php deleted file mode 100644 index 51067e1a5a1..00000000000 --- a/lib/horde/framework/Horde/Idna/Translation.php +++ /dev/null @@ -1,40 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/bsd BSD - * @package Idna - */ - -/** - * Horde_Idna_Translation is the translation wrapper class for - * Horde_Idna. - * - * @author Jan Schneider - * @category Horde - * @copyright 2017 Horde LLC - * @license http://www.horde.org/licenses/bsd BSD - * @package Idna - * @since Horde_Idna 1.1.0 - */ -class Horde_Idna_Translation extends Horde_Translation_Autodetect -{ - /** - * The translation domain - * - * @var string - */ - protected static $_domain = 'Horde_Idna'; - - /** - * The absolute PEAR path to the translations for the default gettext handler. - * - * @var string - */ - protected static $_pearDirectory = '@data_dir@'; -} diff --git a/lib/horde/framework/Horde/Imap/Client.php b/lib/horde/framework/Horde/Imap/Client.php deleted file mode 100644 index d03173d3fb4..00000000000 --- a/lib/horde/framework/Horde/Imap/Client.php +++ /dev/null @@ -1,203 +0,0 @@ - - * @category Horde - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client -{ - /* Constants for openMailbox() */ - const OPEN_READONLY = 1; - const OPEN_READWRITE = 2; - const OPEN_AUTO = 3; - - /* Constants for listMailboxes() */ - const MBOX_SUBSCRIBED = 1; - const MBOX_SUBSCRIBED_EXISTS = 2; - const MBOX_UNSUBSCRIBED = 3; - const MBOX_ALL = 4; - /* @since 2.23.0 */ - const MBOX_ALL_SUBSCRIBED = 5; - - /* Constants for status() */ - const STATUS_MESSAGES = 1; - const STATUS_RECENT = 2; - const STATUS_UIDNEXT = 4; - const STATUS_UIDVALIDITY = 8; - const STATUS_UNSEEN = 16; - const STATUS_ALL = 32; - const STATUS_FIRSTUNSEEN = 64; - const STATUS_FLAGS = 128; - const STATUS_PERMFLAGS = 256; - const STATUS_HIGHESTMODSEQ = 512; - const STATUS_SYNCMODSEQ = 1024; - const STATUS_SYNCFLAGUIDS = 2048; - const STATUS_UIDNOTSTICKY = 4096; - const STATUS_UIDNEXT_FORCE = 8192; - const STATUS_SYNCVANISHED = 16384; - /* @since 2.12.0 */ - const STATUS_RECENT_TOTAL = 32768; - /* @since 2.14.0 */ - const STATUS_FORCE_REFRESH = 65536; - - /* Constants for search() */ - const SORT_ARRIVAL = 1; - const SORT_CC = 2; - const SORT_DATE = 3; - const SORT_FROM = 4; - const SORT_REVERSE = 5; - const SORT_SIZE = 6; - const SORT_SUBJECT = 7; - const SORT_TO = 8; - /* SORT_THREAD provided for completeness - it is not a valid sort criteria - * for search() (use thread() instead). */ - const SORT_THREAD = 9; - /* Sort criteria defined in RFC 5957 */ - const SORT_DISPLAYFROM = 10; - const SORT_DISPLAYTO = 11; - /* SORT_SEQUENCE does a simple numerical sort on the returned - * UIDs/sequence numbers. */ - const SORT_SEQUENCE = 12; - /* Fuzzy sort criteria defined in RFC 6203 */ - const SORT_RELEVANCY = 13; - /* @since 2.4.0 */ - const SORT_DISPLAYFROM_FALLBACK = 14; - /* @since 2.4.0 */ - const SORT_DISPLAYTO_FALLBACK = 15; - - /* Search results constants */ - const SEARCH_RESULTS_COUNT = 1; - const SEARCH_RESULTS_MATCH = 2; - const SEARCH_RESULTS_MAX = 3; - const SEARCH_RESULTS_MIN = 4; - const SEARCH_RESULTS_SAVE = 5; - /* Fuzzy sort criteria defined in RFC 6203 */ - const SEARCH_RESULTS_RELEVANCY = 6; - - /* Constants for thread() */ - const THREAD_ORDEREDSUBJECT = 1; - const THREAD_REFERENCES = 2; - const THREAD_REFS = 3; - - /* Fetch criteria constants. */ - const FETCH_STRUCTURE = 1; - const FETCH_FULLMSG = 2; - const FETCH_HEADERTEXT = 3; - const FETCH_BODYTEXT = 4; - const FETCH_MIMEHEADER = 5; - const FETCH_BODYPART = 6; - const FETCH_BODYPARTSIZE = 7; - const FETCH_HEADERS = 8; - const FETCH_ENVELOPE = 9; - const FETCH_FLAGS = 10; - const FETCH_IMAPDATE = 11; - const FETCH_SIZE = 12; - const FETCH_UID = 13; - const FETCH_SEQ = 14; - const FETCH_MODSEQ = 15; - /* @since 2.11.0 */ - const FETCH_DOWNGRADED = 16; - - /* Namespace constants. @deprecated */ - const NS_PERSONAL = 1; - const NS_OTHER = 2; - const NS_SHARED = 3; - - /* ACL constants (RFC 4314 [2.1]). */ - const ACL_LOOKUP = 'l'; - const ACL_READ = 'r'; - const ACL_SEEN = 's'; - const ACL_WRITE = 'w'; - const ACL_INSERT = 'i'; - const ACL_POST = 'p'; - const ACL_CREATEMBOX = 'k'; - const ACL_DELETEMBOX = 'x'; - const ACL_DELETEMSGS = 't'; - const ACL_EXPUNGE = 'e'; - const ACL_ADMINISTER = 'a'; - // Old constants (RFC 2086 [3]; RFC 4314 [2.1.1]) - const ACL_CREATE = 'c'; - const ACL_DELETE = 'd'; - - /* System flags. */ - // RFC 3501 [2.3.2] - const FLAG_ANSWERED = '\\answered'; - const FLAG_DELETED = '\\deleted'; - const FLAG_DRAFT = '\\draft'; - const FLAG_FLAGGED = '\\flagged'; - const FLAG_RECENT = '\\recent'; - const FLAG_SEEN = '\\seen'; - // RFC 3503 [3.3] - const FLAG_MDNSENT = '$mdnsent'; - // RFC 5550 [2.8] - const FLAG_FORWARDED = '$forwarded'; - // RFC 5788 registered keywords: - // http://www.ietf.org/mail-archive/web/morg/current/msg00441.html - const FLAG_JUNK = '$junk'; - const FLAG_NOTJUNK = '$notjunk'; - - /* Special-use mailbox attributes (RFC 6154 [2]). */ - const SPECIALUSE_ALL = '\\All'; - const SPECIALUSE_ARCHIVE = '\\Archive'; - const SPECIALUSE_DRAFTS = '\\Drafts'; - const SPECIALUSE_FLAGGED = '\\Flagged'; - const SPECIALUSE_JUNK = '\\Junk'; - const SPECIALUSE_SENT = '\\Sent'; - const SPECIALUSE_TRASH = '\\Trash'; - - /* Constants for sync(). */ - const SYNC_UIDVALIDITY = 0; - const SYNC_FLAGS = 1; - const SYNC_FLAGSUIDS = 2; - const SYNC_NEWMSGS = 4; - const SYNC_NEWMSGSUIDS = 8; - const SYNC_VANISHED = 16; - const SYNC_VANISHEDUIDS = 32; - const SYNC_ALL = 64; - - /** - * Capability dependencies. - * - * @deprecated - * - * @var array - */ - public static $capability_deps = array( - // RFC 7162 [3.2] - 'QRESYNC' => array( - // QRESYNC requires CONDSTORE, but the latter is implied and is - // not required to be listed. - 'ENABLE' - ), - // RFC 5182 [2.1] - 'SEARCHRES' => array( - 'ESEARCH' - ), - // RFC 5255 [3.1] - 'LANGUAGE' => array( - 'NAMESPACE' - ), - // RFC 5957 [1] - 'SORT=DISPLAY' => array( - 'SORT' - ) - ); - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Auth/DigestMD5.php b/lib/horde/framework/Horde/Imap/Client/Auth/DigestMD5.php deleted file mode 100644 index bbeeb4ec40b..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Auth/DigestMD5.php +++ /dev/null @@ -1,189 +0,0 @@ - - * @author Michael Slusarz - * @copyright 2002-2003 Richard Heyes - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Auth_DigestMD5 -{ - /** - * Digest response components. - * - * @var string - */ - protected $_response; - - /** - * Generate the Digest-MD5 response. - * - * @param string $id Authentication id (username). - * @param string $pass Password. - * @param string $challenge The digest challenge sent by the server. - * @param string $hostname The hostname of the machine connecting to. - * @param string $service The service name (e.g. 'imap', 'pop3'). - * - * @throws Horde_Imap_Client_Exception - */ - public function __construct($id, $pass, $challenge, $hostname, $service) - { - $challenge = $this->_parseChallenge($challenge); - $cnonce = $this->_getCnonce(); - $digest_uri = sprintf('%s/%s', $service, $hostname); - - /* Get response value. */ - $A1 = sprintf('%s:%s:%s', pack('H32', hash('md5', sprintf('%s:%s:%s', $id, $challenge['realm'], $pass))), $challenge['nonce'], $cnonce); - $A2 = 'AUTHENTICATE:' . $digest_uri; - $response_value = hash('md5', sprintf('%s:%s:00000001:%s:auth:%s', hash('md5', $A1), $challenge['nonce'], $cnonce, hash('md5', $A2))); - - $this->_response = array( - 'cnonce' => '"' . $cnonce . '"', - 'digest-uri' => '"' . $digest_uri . '"', - 'maxbuf' => $challenge['maxbuf'], - 'nc' => '00000001', - 'nonce' => '"' . $challenge['nonce'] . '"', - 'qop' => 'auth', - 'response' => $response_value, - 'username' => '"' . $id . '"' - ); - - if (strlen($challenge['realm'])) { - $this->_response['realm'] = '"' . $challenge['realm'] . '"'; - } - } - - /** - * Cooerce to string. - * - * @return string The digest response (not base64 encoded). - */ - public function __toString() - { - $out = array(); - foreach ($this->_response as $key => $val) { - $out[] = $key . '=' . $val; - } - return implode(',', $out); - } - - /** - * Return specific digest response directive. - * - * @return mixed Requested directive, or null if it does not exist. - */ - public function __get($name) - { - return isset($this->_response[$name]) - ? $this->_response[$name] - : null; - } - - /** - * Parses and verifies the digest challenge. - * - * @param string $challenge The digest challenge - * - * @return array The parsed challenge as an array with directives as keys. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _parseChallenge($challenge) - { - $tokens = array( - 'maxbuf' => 65536, - 'realm' => '' - ); - - preg_match_all('/([a-z-]+)=("[^"]+(? - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.29.0 - */ -class Horde_Imap_Client_Auth_Scram -{ - /** - * AuthMessage (RFC 5802 [3]). - * - * @var string - */ - protected $_authmsg; - - /** - * Hash name. - * - * @var string - */ - protected $_hash; - - /** - * Number of Hi iterations (RFC 5802 [2]). - * - * @var integer - */ - protected $_iterations; - - /** - * Nonce. - * - * @var string - */ - protected $_nonce; - - /** - * Password. - * - * @var string - */ - protected $_pass; - - /** - * Server salt. - * - * @var string - */ - protected $_salt; - - /** - * Calculated server signature value. - * - * @var string - */ - protected $_serversig; - - /** - * Username. - * - * @var string - */ - protected $_user; - - /** - * Constructor. - * - * @param string $user Username. - * @param string $pass Password. - * @param string $hash Hash name. - * - * @throws Horde_Imap_Client_Exception - */ - public function __construct($user, $pass, $hash = 'SHA1') - { - $error = false; - - $this->_hash = $hash; - - try { - if (!class_exists('Horde_Stringprep') || - !class_exists('Horde_Crypt_Blowfish_Pbkdf2')) { - throw new Exception(); - } - - Horde_Stringprep::autoload(); - $saslprep = new Znerol\Component\Stringprep\Profile\SASLprep(); - - $this->_user = $saslprep->apply( - $user, - 'UTF-8', - Znerol\Component\Stringprep\Profile::MODE_QUERY - ); - $this->_pass = $saslprep->apply( - $pass, - 'UTF-8', - Znerol\Component\Stringprep\Profile::MODE_STORE - ); - } catch (Znerol\Component\Stringprep\ProfileException $e) { - $error = true; - } catch (Exception $e) { - $error = true; - } - - if ($error) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Authentication failure."), - Horde_Imap_Client_Exception::LOGIN_AUTHORIZATIONFAILED - ); - } - - /* Generate nonce. (Done here so this can be overwritten for - * testing purposes.) */ - $this->_nonce = strval(new Horde_Support_Randomid()); - } - - /** - * Return the initial client message. - * - * @return string Initial client message. - */ - public function getClientFirstMessage() - { - /* n: client doesn't support channel binding, - * , - * n=: SASLprepped username with "," and "=" escaped, - * r=: Random nonce */ - $this->_authmsg = 'n=' . str_replace( - array(',', '='), - array('=2C', '=3D'), - $this->_user - ) . ',r=' . $this->_nonce; - - return 'n,,' . $this->_authmsg; - } - - /** - * Process the initial server message response. - * - * @param string $msg Initial server response. - * - * @return boolean False if authentication failed at this stage. - */ - public function parseServerFirstMessage($msg) - { - $i = $r = $s = false; - - foreach (explode(',', $msg) as $val) { - list($attr, $aval) = array_map('trim', explode('=', $val, 2)); - - switch ($attr) { - case 'i': - $this->_iterations = intval($aval); - $i = true; - break; - - case 'r': - /* Beginning of server-provided nonce MUST be the same as the - * nonce we provided. */ - if (strpos($aval, $this->_nonce) !== 0) { - return false; - } - $this->_nonce = $aval; - $r = true; - break; - - case 's': - $this->_salt = base64_decode($aval); - $s = true; - break; - } - } - - if ($i && $r && $s) { - $this->_authmsg .= ',' . $msg; - return true; - } - - return false; - } - - /** - * Return the final client message. - * - * @return string Final client message. - */ - public function getClientFinalMessage() - { - $final_msg = 'c=biws,r=' . $this->_nonce; - - /* Salted password. */ - $s_pass = strval(new Horde_Crypt_Blowfish_Pbkdf2( - $this->_pass, - strlen(hash($this->_hash, '', true)), - array( - 'algo' => $this->_hash, - 'i_count' => $this->_iterations, - 'salt' => $this->_salt - ) - )); - - /* Client key. */ - $c_key = hash_hmac($this->_hash, 'Client Key', $s_pass, true); - - /* Stored key. */ - $s_key = hash($this->_hash, $c_key, true); - - /* Client signature. */ - $auth_msg = $this->_authmsg . ',' . $final_msg; - $c_sig = hash_hmac($this->_hash, $auth_msg, $s_key, true); - - /* Proof. */ - $proof = $c_key ^ $c_sig; - - /* Server signature. */ - $this->_serversig = hash_hmac( - $this->_hash, - $auth_msg, - hash_hmac($this->_hash, 'Server Key', $s_pass, true), - true - ); - - /* c=biws: channel-binding ("biws" = base64('n,,')), - * p=: base64 encoded ClientProof, - * r=: Nonce as returned from the server. */ - return $final_msg . ',p=' . base64_encode($proof); - } - - /** - * Process the final server message response. - * - * @param string $msg Final server response. - * - * @return boolean False if authentication failed. - */ - public function parseServerFinalMessage($msg) - { - foreach (explode(',', $msg) as $val) { - list($attr, $aval) = array_map('trim', explode('=', $val, 2)); - - switch ($attr) { - case 'e': - return false; - - case 'v': - return (base64_decode($aval) === $this->_serversig); - } - } - - return false; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Base.php b/lib/horde/framework/Horde/Imap/Client/Base.php deleted file mode 100644 index f6eb80ee21a..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Base.php +++ /dev/null @@ -1,4096 +0,0 @@ - - * @category Horde - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * - * @property-read Horde_Imap_Client_Base_Alert $alerts_ob - The alert reporting object (@since 2.26.0) - * @property-read Horde_Imap_Client_Data_Capability $capability - * A capability object. (@since 2.24.0) - * @property-read Horde_Imap_Client_Data_SearchCharset $search_charset - * A search charset object. (@since 2.24.0) - * @property-read Horde_Imap_Client_Url $url The URL object for the current - * connection parameters (@since 2.24.0) - */ -abstract class Horde_Imap_Client_Base -implements Serializable, SplObserver -{ - /** Serialized version. */ - const VERSION = 3; - - /** Cache names for miscellaneous data. */ - const CACHE_MODSEQ = '_m'; - const CACHE_SEARCH = '_s'; - /* @since 2.9.0 */ - const CACHE_SEARCHID = '_i'; - - /** Cache names used exclusively within this class. @since 2.11.0 */ - const CACHE_DOWNGRADED = 'HICdg'; - - /** - * The list of fetch fields that can be cached, and their cache names. - * - * @var array - */ - public $cacheFields = array( - Horde_Imap_Client::FETCH_ENVELOPE => 'HICenv', - Horde_Imap_Client::FETCH_FLAGS => 'HICflags', - Horde_Imap_Client::FETCH_HEADERS => 'HIChdrs', - Horde_Imap_Client::FETCH_IMAPDATE => 'HICdate', - Horde_Imap_Client::FETCH_SIZE => 'HICsize', - Horde_Imap_Client::FETCH_STRUCTURE => 'HICstruct' - ); - - /** - * Has the internal configuration changed? - * - * @var boolean - */ - public $changed = false; - - /** - * Horde_Imap_Client is optimized for short (i.e. 1 seconds) scripts. It - * makes heavy use of mailbox caching to save on server accesses. This - * property should be set to false for long-running scripts, or else - * status() data may not reflect the current state of the mailbox on the - * server. - * - * @since 2.14.0 - * - * @var boolean - */ - public $statuscache = true; - - /** - * Alerts reporting object. - * - * @var Horde_Imap_Client_Base_Alerts - */ - protected $_alerts; - - /** - * The Horde_Imap_Client_Cache object. - * - * @var Horde_Imap_Client_Cache - */ - protected $_cache = null; - - /** - * Connection to the IMAP server. - * - * @var Horde\Socket\Client - */ - protected $_connection = null; - - /** - * The debug object. - * - * @var Horde_Imap_Client_Base_Debug - */ - protected $_debug = null; - - /** - * The default ports to use for a connection. - * First element is non-secure, second is SSL. - * - * @var array - */ - protected $_defaultPorts = array(); - - /** - * The fetch data object type to return. - * - * @var string - */ - protected $_fetchDataClass = 'Horde_Imap_Client_Data_Fetch'; - - /** - * Cached server data. - * - * @var array - */ - protected $_init; - - /** - * Is there an active authenticated connection to the IMAP Server? - * - * @var boolean - */ - protected $_isAuthenticated = false; - - /** - * The current mailbox selection mode. - * - * @var integer - */ - protected $_mode = 0; - - /** - * Hash containing connection parameters. - * This hash never changes. - * - * @var array - */ - protected $_params = array(); - - /** - * The currently selected mailbox. - * - * @var Horde_Imap_Client_Mailbox - */ - protected $_selected = null; - - /** - * Temp array (destroyed at end of process). - * - * @var array - */ - protected $_temp = array(); - - /** - * Constructor. - * - * @param array $params Configuration parameters: - *
-     * - cache: (array) If set, caches data from fetch(), search(), and
-     *          thread() calls. Requires the horde/Cache package to be
-     *          installed. The array can contain the following keys (see
-     *          Horde_Imap_Client_Cache for default values):
-     *   - backend: [REQUIRED (or cacheob)] (Horde_Imap_Client_Cache_Backend)
-     *              Backend cache driver [@since 2.9.0].
-     *   - fetch_ignore: (array) A list of mailboxes to ignore when storing
-     *                   fetch data.
-     *   - fields: (array) The fetch criteria to cache. If not defined, all
-     *             cacheable data is cached. The following is a list of
-     *             criteria that can be cached:
-     *     - Horde_Imap_Client::FETCH_ENVELOPE
-     *     - Horde_Imap_Client::FETCH_FLAGS
-     *       Only if server supports CONDSTORE extension
-     *     - Horde_Imap_Client::FETCH_HEADERS
-     *       Only for queries that specifically request caching
-     *     - Horde_Imap_Client::FETCH_IMAPDATE
-     *     - Horde_Imap_Client::FETCH_SIZE
-     *     - Horde_Imap_Client::FETCH_STRUCTURE
-     * - capability_ignore: (array) A list of IMAP capabilites to ignore, even
-     *                      if they are supported on the server.
-     *                      DEFAULT: No supported capabilities are ignored.
-     * - comparator: (string) The search comparator to use instead of the
-     *               default server comparator. See setComparator() for
-     *               format.
-     *               DEFAULT: Use the server default
-     * - context: (array) Any context parameters passed to
-     *            stream_create_context(). @since 2.27.0
-     * - debug: (string) If set, will output debug information to the stream
-     *          provided. The value can be any PHP supported wrapper that can
-     *          be opened via PHP's fopen() function.
-     *          DEFAULT: No debug output
-     * - hostspec: (string) The hostname or IP address of the server.
-     *             DEFAULT: 'localhost'
-     * - id: (array) Send ID information to the server (only if server
-     *       supports the ID extension). An array with the keys as the fields
-     *       to send and the values being the associated values. See RFC 2971
-     *       [3.3] for a list of standard field values.
-     *       DEFAULT: No info sent to server
-     * - lang: (array) A list of languages (in priority order) to be used to
-     *         display human readable messages.
-     *         DEFAULT: Messages output in IMAP server default language
-     * - password: (mixed) The user password. Either a string or a
-     *             Horde_Imap_Client_Base_Password object [@since 2.14.0].
-     * - port: (integer) The server port to which we will connect.
-     *         DEFAULT: 143 (imap or imap w/TLS) or 993 (imaps)
-     * - secure: (string) Use SSL or TLS to connect. Values:
-     *   - false (No encryption)
-     *   - 'ssl' (Auto-detect SSL version)
-     *   - 'sslv2' (Force SSL version 3)
-     *   - 'sslv3' (Force SSL version 2)
-     *   - 'tls' (TLS; started via protocol-level negotation over
-     *     unencrypted channel; RECOMMENDED way of initiating secure
-     *     connection)
-     *   - 'tlsv1' (TLS direct version 1.x connection to server) [@since
-     *     2.16.0]
-     *   - true (TLS if available/necessary) [@since 2.15.0]
-     *     DEFAULT: false
-     * - timeout: (integer)  Connection timeout, in seconds.
-     *            DEFAULT: 30 seconds
-     * - username: (string) [REQUIRED] The username.
-     * - authusername (string) The username used for SASL authentication.
-     * 	 If specified this is the user name whose password is used
-     * 	 (e.g. administrator).
-     * 	 Only valid for RFC 2595/4616 - PLAIN SASL mechanism.
-     * 	 DEFAULT: the same value provided in the username parameter.
-     * 
- */ - public function __construct(array $params = array()) - { - if (!isset($params['username'])) { - throw new InvalidArgumentException('Horde_Imap_Client requires a username.'); - } - - $this->_setInit(); - - // Default values. - $params = array_merge(array( - 'context' => array(), - 'hostspec' => 'localhost', - 'secure' => false, - 'timeout' => 30 - ), array_filter($params)); - - if (!isset($params['port']) && strpos($params['hostspec'], 'unix://') !== 0) { - $params['port'] = (!empty($params['secure']) && in_array($params['secure'], array('ssl', 'sslv2', 'sslv3'), true)) - ? $this->_defaultPorts[1] - : $this->_defaultPorts[0]; - } - - if (empty($params['cache'])) { - $params['cache'] = array('fields' => array()); - } elseif (empty($params['cache']['fields'])) { - $params['cache']['fields'] = $this->cacheFields; - } else { - $params['cache']['fields'] = array_flip($params['cache']['fields']); - } - - if (empty($params['cache']['fetch_ignore'])) { - $params['cache']['fetch_ignore'] = array(); - } - - $this->_params = $params; - if (isset($params['password'])) { - $this->setParam('password', $params['password']); - } - - $this->changed = true; - $this->_initOb(); - } - - /** - * Get encryption key. - * - * @deprecated Pass callable into 'password' parameter instead. - * - * @return string The encryption key. - */ - protected function _getEncryptKey() - { - if (is_callable($ekey = $this->getParam('encryptKey'))) { - return call_user_func($ekey); - } - - throw new InvalidArgumentException('encryptKey parameter is not a valid callback.'); - } - - /** - * Do initialization tasks. - */ - protected function _initOb() - { - register_shutdown_function(array($this, 'shutdown')); - - $this->_alerts = new Horde_Imap_Client_Base_Alerts(); - // @todo: Remove (BC) - $this->_alerts->attach($this); - - $this->_debug = ($debug = $this->getParam('debug')) - ? new Horde_Imap_Client_Base_Debug($debug) - : new Horde_Support_Stub(); - - // @todo: Remove (BC purposes) - if (isset($this->_init['capability']) && - !is_object($this->_init['capability'])) { - $this->_setInit('capability'); - } - - foreach (array('capability', 'search_charset') as $val) { - if (isset($this->_init[$val])) { - $this->_init[$val]->attach($this); - } - } - } - - /** - * Shutdown actions. - */ - public function shutdown() - { - try { - $this->logout(); - } catch (Horde_Imap_Client_Exception $e) { - } - } - - /** - * This object can not be cloned. - */ - public function __clone() - { - throw new LogicException('Object cannot be cloned.'); - } - - /** - */ - #[ReturnTypeWillChange] - public function update(SplSubject $subject) - { - if (($subject instanceof Horde_Imap_Client_Data_Capability) || - ($subject instanceof Horde_Imap_Client_Data_SearchCharset)) { - $this->changed = true; - } - - /* @todo: BC - remove */ - if ($subject instanceof Horde_Imap_Client_Base_Alerts) { - $this->_temp['alerts'][] = $subject->getLast()->alert; - } - } - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version change'); - } - $this->__unserialize($data); - } - - /** - * @return array - */ - public function __serialize() - { - return array( - 'i' => $this->_init, - 'p' => $this->_params, - 'v' => self::VERSION - ); - } - - public function __unserialize(array $data) - { - if (empty($data['v']) || $data['v'] != self::VERSION) { - throw new Exception('Cache version change'); - } - - $this->_init = $data['i']; - $this->_params = $data['p']; - - $this->_initOb(); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'alerts_ob': - return $this->_alerts; - - case 'capability': - return $this->_capability(); - - case 'search_charset': - if (!isset($this->_init['search_charset'])) { - $this->_init['search_charset'] = new Horde_Imap_Client_Data_SearchCharset(); - $this->_init['search_charset']->attach($this); - } - $this->_init['search_charset']->setBaseOb($this); - return $this->_init['search_charset']; - - case 'url': - $url = new Horde_Imap_Client_Url(); - $url->hostspec = $this->getParam('hostspec'); - $url->port = $this->getParam('port'); - $url->protocol = 'imap'; - return $url; - } - } - - /** - * Set an initialization value. - * - * @param string $key The initialization key. If null, resets all keys. - * @param mixed $val The cached value. If null, removes the key. - */ - public function _setInit($key = null, $val = null) - { - if (is_null($key)) { - $this->_init = array(); - } elseif (is_null($val)) { - unset($this->_init[$key]); - } else { - switch ($key) { - case 'capability': - if ($ci = $this->getParam('capability_ignore')) { - $ignored = array(); - - foreach ($ci as $val2) { - $c = explode('=', $val2); - - if ($val->query($c[0], isset($c[1]) ? $c[1] : null)) { - $ignored[] = $val2; - $val->remove($c[0], isset($c[1]) ? $c[1] : null); - } - } - - if ($this->_debug->debug && !empty($ignored)) { - $this->_debug->info(sprintf( - 'CONFIG: IGNORING these IMAP capabilities: %s', - implode(', ', $ignored) - )); - } - } - - $val->attach($this); - break; - } - - /* Nothing has changed. */ - if (isset($this->_init[$key]) && ($this->_init[$key] === $val)) { - return; - } - - $this->_init[$key] = $val; - } - - $this->changed = true; - } - - /** - * Initialize the Horde_Imap_Client_Cache object, if necessary. - * - * @param boolean $current If true, we are going to update the currently - * selected mailbox. Add an additional check to - * see if caching is available in current - * mailbox. - * - * @return boolean Returns true if caching is enabled. - */ - protected function _initCache($current = false) - { - $c = $this->getParam('cache'); - - if (empty($c['fields'])) { - return false; - } - - if (is_null($this->_cache)) { - if (isset($c['backend'])) { - $backend = $c['backend']; - } elseif (isset($c['cacheob'])) { - /* Deprecated */ - $backend = new Horde_Imap_Client_Cache_Backend_Cache($c); - } else { - return false; - } - - $this->_cache = new Horde_Imap_Client_Cache(array( - 'backend' => $backend, - 'baseob' => $this, - 'debug' => $this->_debug - )); - } - - return $current - /* If UIDs are labeled as not sticky, don't cache since UIDs will - * change on every access. */ - ? !($this->_mailboxOb()->getStatus(Horde_Imap_Client::STATUS_UIDNOTSTICKY)) - : true; - } - - /** - * Returns a value from the internal params array. - * - * @param string $key The param key. - * - * @return mixed The param value, or null if not found. - */ - public function getParam($key) - { - /* Passwords may be stored encrypted. */ - switch ($key) { - case 'password': - if (isset($this->_params[$key]) && - ($this->_params[$key] instanceof Horde_Imap_Client_Base_Password)) { - return $this->_params[$key]->getPassword(); - } - - // DEPRECATED - if (!empty($this->_params['_passencrypt'])) { - try { - $secret = new Horde_Secret(); - return $secret->read($this->_getEncryptKey(), $this->_params['password']); - } catch (Exception $e) { - return null; - } - } - break; - } - - return isset($this->_params[$key]) - ? $this->_params[$key] - : null; - } - - /** - * Sets a configuration parameter value. - * - * @param string $key The param key. - * @param mixed $val The param value. - */ - public function setParam($key, $val) - { - switch ($key) { - case 'password': - if ($val instanceof Horde_Imap_Client_Base_Password) { - break; - } - - // DEPRECATED: Encrypt password. - try { - $encrypt_key = $this->_getEncryptKey(); - if (strlen($encrypt_key)) { - $secret = new Horde_Secret(); - $val = $secret->write($encrypt_key, $val); - $this->_params['_passencrypt'] = true; - } - } catch (Exception $e) {} - break; - } - - $this->_params[$key] = $val; - $this->changed = true; - } - - /** - * Returns the Horde_Imap_Client_Cache object used, if available. - * - * @return mixed Either the cache object or null. - */ - public function getCache() - { - $this->_initCache(); - return $this->_cache; - } - - /** - * Returns the correct IDs object for use with this driver. - * - * @param mixed $ids Either self::ALL, self::SEARCH_RES, self::LARGEST, - * Horde_Imap_Client_Ids object, array, or sequence - * string. - * @param boolean $sequence Are $ids message sequence numbers? - * - * @return Horde_Imap_Client_Ids The IDs object. - */ - public function getIdsOb($ids = null, $sequence = false) - { - return new Horde_Imap_Client_Ids($ids, $sequence); - } - - /** - * Returns whether the IMAP server supports the given capability - * (See RFC 3501 [6.1.1]). - * - * @deprecated Use $capability property instead. - * - * @param string $capability The capability string to query. - * - * @return mixed True if the server supports the queried capability, - * false if it doesn't, or an array if the capability can - * contain multiple values. - */ - public function queryCapability($capability) - { - try { - $c = $this->_capability(); - return ($out = $c->getParams($capability)) - ? $out - : $c->query($capability); - } catch (Horde_Imap_Client_Exception $e) { - return false; - } - } - - /** - * Get CAPABILITY information from the IMAP server. - * - * @deprecated Use $capability property instead. - * - * @return array The capability array. - * - * @throws Horde_Imap_Client_Exception - */ - public function capability() - { - return $this->_capability()->toArray(); - } - - /** - * Query server capability. - * - * Required because internal code can't call capability via magic method - * directly - it may not exist yet, the creation code may call capability - * recursively, and __get() doesn't allow recursive calls to the same - * property (chicken/egg issue). - * - * @return mixed The capability object if no arguments provided. If - * arguments are provided, they are passed to the query() - * method and this value is returned. - * @throws Horde_Imap_Client_Exception - */ - protected function _capability() - { - if (!isset($this->_init['capability'])) { - $this->_initCapability(); - } - - return ($args = func_num_args()) - ? $this->_init['capability']->query(func_get_arg(0), ($args > 1) ? func_get_arg(1) : null) - : $this->_init['capability']; - } - - /** - * Retrieve capability information from the IMAP server. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _initCapability(); - - /** - * Send a NOOP command (RFC 3501 [6.1.2]). - * - * @throws Horde_Imap_Client_Exception - */ - public function noop() - { - if (!$this->_connection) { - // NOOP can be called in the unauthenticated state. - $this->_connect(); - } - $this->_noop(); - } - - /** - * Send a NOOP command. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _noop(); - - /** - * Get the NAMESPACE information from the IMAP server (RFC 2342). - * - * @param array $additional If the server supports namespaces, any - * additional namespaces to add to the - * namespace list that are not broadcast by - * the server. The namespaces must be UTF-8 - * strings. - * @param array $opts Additional options: - * - ob_return: (boolean) If true, returns a - * Horde_Imap_Client_Namespace_List object instead of an - * array. - * - * @return mixed A Horde_Imap_Client_Namespace_List object if - * 'ob_return', is true. Otherwise, an array of namespace - * objects (@deprecated) with the name as the key (UTF-8) - * and the following values: - *
-     *  - delimiter: (string) The namespace delimiter.
-     *  - hidden: (boolean) Is this a hidden namespace?
-     *  - name: (string) The namespace name (UTF-8).
-     *  - translation: (string) Returns the translated name of the namespace
-     *                 (UTF-8). Requires RFC 5255 and a previous call to
-     *                 setLanguage().
-     *  - type: (integer) The namespace type. Either:
-     *    - Horde_Imap_Client::NS_PERSONAL
-     *    - Horde_Imap_Client::NS_OTHER
-     *    - Horde_Imap_Client::NS_SHARED
-     * 
- * - * @throws Horde_Imap_Client_Exception - */ - public function getNamespaces( - array $additional = array(), array $opts = array() - ) - { - $additional = array_map('strval', $additional); - $sig = hash( - 'md5', - json_encode($additional) . intval(empty($opts['ob_return'])) - ); - - if (isset($this->_init['namespace'][$sig])) { - $ns = $this->_init['namespace'][$sig]; - } else { - $this->login(); - - $ns = $this->_getNamespaces(); - - /* Skip namespaces if we have already auto-detected them. Also, - * hidden namespaces cannot be empty. */ - $to_process = array_diff(array_filter($additional, 'strlen'), array_map('strlen', iterator_to_array($ns))); - if (!empty($to_process)) { - foreach ($this->listMailboxes($to_process, Horde_Imap_Client::MBOX_ALL, array('delimiter' => true)) as $key => $val) { - $ob = new Horde_Imap_Client_Data_Namespace(); - $ob->delimiter = $val['delimiter']; - $ob->hidden = true; - $ob->name = $key; - $ob->type = $ob::NS_SHARED; - $ns[$val] = $ob; - } - } - - if (!count($ns)) { - /* This accurately determines the namespace information of the - * base namespace if the NAMESPACE command is not supported. - * See: RFC 3501 [6.3.8] */ - $mbox = $this->listMailboxes('', Horde_Imap_Client::MBOX_ALL, array('delimiter' => true)); - $first = reset($mbox); - - $ob = new Horde_Imap_Client_Data_Namespace(); - $ob->delimiter = $first['delimiter']; - $ns[''] = $ob; - } - - $this->_init['namespace'][$sig] = $ns; - $this->_setInit('namespace', $this->_init['namespace']); - } - - if (!empty($opts['ob_return'])) { - return $ns; - } - - /* @todo Remove for 3.0 */ - $out = array(); - foreach ($ns as $key => $val) { - $out[$key] = array( - 'delimiter' => $val->delimiter, - 'hidden' => $val->hidden, - 'name' => $val->name, - 'translation' => $val->translation, - 'type' => $val->type - ); - } - - return $out; - } - - /** - * Get the NAMESPACE information from the IMAP server. - * - * @return Horde_Imap_Client_Namespace_List Namespace list object. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _getNamespaces(); - - /** - * Display if connection to the server has been secured via TLS or SSL. - * - * @return boolean True if the IMAP connection is secured. - */ - public function isSecureConnection() - { - return ($this->_connection && $this->_connection->secure); - } - - /** - * Connect to the remote server. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _connect(); - - /** - * Return a list of alerts that MUST be presented to the user (RFC 3501 - * [7.1]). - * - * @deprecated Add an observer to the $alerts_ob property instead. - * - * @return array An array of alert messages. - */ - public function alerts() - { - $alerts = isset($this->_temp['alerts']) - ? $this->_temp['alerts'] - : array(); - unset($this->_temp['alerts']); - return $alerts; - } - - /** - * Login to the IMAP server. - * - * @throws Horde_Imap_Client_Exception - */ - public function login() - { - if (!$this->_isAuthenticated && $this->_login()) { - if ($this->getParam('id')) { - try { - $this->sendID(); - /* ID is queued - force sending the queued command. */ - $this->_sendCmd($this->_pipeline()); - } catch (Horde_Imap_Client_Exception_NoSupportExtension $e) { - // Ignore if server doesn't support ID extension. - } - } - - if ($this->getParam('comparator')) { - try { - $this->setComparator(); - } catch (Horde_Imap_Client_Exception_NoSupportExtension $e) { - // Ignore if server doesn't support I18NLEVEL=2 - } - } - } - - $this->_isAuthenticated = true; - } - - /** - * Login to the IMAP server. - * - * @return boolean Return true if global login tasks should be run. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _login(); - - /** - * Logout from the IMAP server (see RFC 3501 [6.1.3]). - */ - public function logout() - { - if ($this->_isAuthenticated && $this->_connection->connected) { - $this->_logout(); - $this->_connection->close(); - } - - $this->_connection = $this->_selected = null; - $this->_isAuthenticated = false; - $this->_mode = 0; - } - - /** - * Logout from the IMAP server (see RFC 3501 [6.1.3]). - */ - abstract protected function _logout(); - - /** - * Send ID information to the IMAP server (RFC 2971). - * - * @param array $info Overrides the value of the 'id' param and sends - * this information instead. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function sendID($info = null) - { - if (!$this->_capability('ID')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('ID'); - } - - $this->_sendID(is_null($info) ? ($this->getParam('id') ?: array()) : $info); - } - - /** - * Send ID information to the IMAP server (RFC 2971). - * - * @param array $info The information to send to the server. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _sendID($info); - - /** - * Return ID information from the IMAP server (RFC 2971). - * - * @return array An array of information returned, with the keys as the - * 'field' and the values as the 'value'. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function getID() - { - if (!$this->_capability('ID')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('ID'); - } - - return $this->_getID(); - } - - /** - * Return ID information from the IMAP server (RFC 2971). - * - * @return array An array of information returned, with the keys as the - * 'field' and the values as the 'value'. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _getID(); - - /** - * Sets the preferred language for server response messages (RFC 5255). - * - * @param array $langs Overrides the value of the 'lang' param and sends - * this list of preferred languages instead. The - * special string 'i-default' can be used to restore - * the language to the server default. - * - * @return string The language accepted by the server, or null if the - * default language is used. - * - * @throws Horde_Imap_Client_Exception - */ - public function setLanguage($langs = null) - { - $lang = null; - - if ($this->_capability('LANGUAGE')) { - $lang = is_null($langs) - ? $this->getParam('lang') - : $langs; - } - - return is_null($lang) - ? null - : $this->_setLanguage($lang); - } - - /** - * Sets the preferred language for server response messages (RFC 5255). - * - * @param array $langs The preferred list of languages. - * - * @return string The language accepted by the server, or null if the - * default language is used. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _setLanguage($langs); - - /** - * Gets the preferred language for server response messages (RFC 5255). - * - * @param array $list If true, return the list of available languages. - * - * @return mixed If $list is true, the list of languages available on the - * server (may be empty). If false, the language used by - * the server, or null if the default language is used. - * - * @throws Horde_Imap_Client_Exception - */ - public function getLanguage($list = false) - { - if (!$this->_capability('LANGUAGE')) { - return $list ? array() : null; - } - - return $this->_getLanguage($list); - } - - /** - * Gets the preferred language for server response messages (RFC 5255). - * - * @param array $list If true, return the list of available languages. - * - * @return mixed If $list is true, the list of languages available on the - * server (may be empty). If false, the language used by - * the server, or null if the default language is used. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _getLanguage($list); - - /** - * Open a mailbox. - * - * @param mixed $mailbox The mailbox to open. Either a - * Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * @param integer $mode The access mode. Either - * - Horde_Imap_Client::OPEN_READONLY - * - Horde_Imap_Client::OPEN_READWRITE - * - Horde_Imap_Client::OPEN_AUTO - * - * @throws Horde_Imap_Client_Exception - */ - public function openMailbox($mailbox, $mode = Horde_Imap_Client::OPEN_AUTO) - { - $this->login(); - - $change = false; - $mailbox = Horde_Imap_Client_Mailbox::get($mailbox); - - if ($mode == Horde_Imap_Client::OPEN_AUTO) { - if (is_null($this->_selected) || - !$mailbox->equals($this->_selected)) { - $mode = Horde_Imap_Client::OPEN_READONLY; - $change = true; - } - } else { - $change = (is_null($this->_selected) || - !$mailbox->equals($this->_selected) || - ($mode != $this->_mode)); - } - - if ($change) { - $this->_openMailbox($mailbox, $mode); - $this->_mailboxOb()->open = true; - if ($this->_initCache(true)) { - $this->_condstoreSync(); - } - } - } - - /** - * Open a mailbox. - * - * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to open. - * @param integer $mode The access mode. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _openMailbox(Horde_Imap_Client_Mailbox $mailbox, - $mode); - - /** - * Called when the selected mailbox is changed. - * - * @param mixed $mailbox The selected mailbox or null. - * @param integer $mode The access mode. - */ - protected function _changeSelected($mailbox = null, $mode = null) - { - $this->_mode = $mode; - if (is_null($mailbox)) { - $this->_selected = null; - } else { - $this->_selected = clone $mailbox; - $this->_mailboxOb()->reset(); - } - } - - /** - * Return the Horde_Imap_Client_Base_Mailbox object. - * - * @param string $mailbox The mailbox name. Defaults to currently - * selected mailbox. - * - * @return Horde_Imap_Client_Base_Mailbox Mailbox object. - */ - protected function _mailboxOb($mailbox = null) - { - $name = is_null($mailbox) - ? strval($this->_selected) - : strval($mailbox); - - if (!isset($this->_temp['mailbox_ob'][$name])) { - $this->_temp['mailbox_ob'][$name] = new Horde_Imap_Client_Base_Mailbox(); - } - - return $this->_temp['mailbox_ob'][$name]; - } - - /** - * Return the currently opened mailbox and access mode. - * - * @return mixed Null if no mailbox selected, or an array with two - * elements: - * - mailbox: (Horde_Imap_Client_Mailbox) The mailbox object. - * - mode: (integer) Current mode. - * - * @throws Horde_Imap_Client_Exception - */ - public function currentMailbox() - { - return is_null($this->_selected) - ? null - : array( - 'mailbox' => clone $this->_selected, - 'mode' => $this->_mode - ); - } - - /** - * Create a mailbox. - * - * @param mixed $mailbox The mailbox to create. Either a - * Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * @param array $opts Additional options: - * - special_use: (array) An array of special-use flags to mark the - * mailbox with. The server MUST support RFC 6154. - * - * @throws Horde_Imap_Client_Exception - */ - public function createMailbox($mailbox, array $opts = array()) - { - $this->login(); - - if (!$this->_capability('CREATE-SPECIAL-USE')) { - unset($opts['special_use']); - } - - $this->_createMailbox(Horde_Imap_Client_Mailbox::get($mailbox), $opts); - } - - /** - * Create a mailbox. - * - * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to create. - * @param array $opts Additional options. See - * createMailbox(). - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _createMailbox(Horde_Imap_Client_Mailbox $mailbox, - $opts); - - /** - * Delete a mailbox. - * - * @param mixed $mailbox The mailbox to delete. Either a - * Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * - * @throws Horde_Imap_Client_Exception - */ - public function deleteMailbox($mailbox) - { - $this->login(); - - $mailbox = Horde_Imap_Client_Mailbox::get($mailbox); - - $this->_deleteMailbox($mailbox); - $this->_deleteMailboxPost($mailbox); - } - - /** - * Delete a mailbox. - * - * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to delete. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _deleteMailbox(Horde_Imap_Client_Mailbox $mailbox); - - /** - * Actions to perform after a mailbox delete. - * - * @param Horde_Imap_Client_Mailbox $mailbox The deleted mailbox. - */ - protected function _deleteMailboxPost(Horde_Imap_Client_Mailbox $mailbox) - { - /* Delete mailbox caches. */ - if ($this->_initCache()) { - $this->_cache->deleteMailbox($mailbox); - } - unset($this->_temp['mailbox_ob'][strval($mailbox)]); - - /* Unsubscribe from mailbox. */ - try { - $this->subscribeMailbox($mailbox, false); - } catch (Horde_Imap_Client_Exception $e) { - // Ignore failed unsubscribe request - } - } - - /** - * Rename a mailbox. - * - * @param mixed $old The old mailbox name. Either a - * Horde_Imap_Client_Mailbox object or a string (UTF-8). - * @param mixed $new The new mailbox name. Either a - * Horde_Imap_Client_Mailbox object or a string (UTF-8). - * - * @throws Horde_Imap_Client_Exception - */ - public function renameMailbox($old, $new) - { - // Login will be handled by first listMailboxes() call. - - $old = Horde_Imap_Client_Mailbox::get($old); - $new = Horde_Imap_Client_Mailbox::get($new); - - /* Check if old mailbox(es) were subscribed to. */ - $base = $this->listMailboxes($old, Horde_Imap_Client::MBOX_SUBSCRIBED, array('delimiter' => true)); - if (empty($base)) { - $base = $this->listMailboxes($old, Horde_Imap_Client::MBOX_ALL, array('delimiter' => true)); - $base = reset($base); - $subscribed = array(); - } else { - $base = reset($base); - $subscribed = array($base['mailbox']); - } - - $all_mboxes = array($base['mailbox']); - if (strlen($base['delimiter'])) { - $search = $old->list_escape . $base['delimiter'] . '*'; - $all_mboxes = array_merge($all_mboxes, $this->listMailboxes($search, Horde_Imap_Client::MBOX_ALL, array('flat' => true))); - $subscribed = array_merge($subscribed, $this->listMailboxes($search, Horde_Imap_Client::MBOX_SUBSCRIBED, array('flat' => true))); - } - - $this->_renameMailbox($old, $new); - - /* Delete mailbox actions. */ - foreach ($all_mboxes as $val) { - $this->_deleteMailboxPost($val); - } - - foreach ($subscribed as $val) { - try { - $this->subscribeMailbox(new Horde_Imap_Client_Mailbox(substr_replace($val, $new, 0, strlen($old)))); - } catch (Horde_Imap_Client_Exception $e) { - // Ignore failed subscription requests - } - } - } - - /** - * Rename a mailbox. - * - * @param Horde_Imap_Client_Mailbox $old The old mailbox name. - * @param Horde_Imap_Client_Mailbox $new The new mailbox name. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _renameMailbox(Horde_Imap_Client_Mailbox $old, - Horde_Imap_Client_Mailbox $new); - - /** - * Manage subscription status for a mailbox. - * - * @param mixed $mailbox The mailbox to [un]subscribe to. Either a - * Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * @param boolean $subscribe True to subscribe, false to unsubscribe. - * - * @throws Horde_Imap_Client_Exception - */ - public function subscribeMailbox($mailbox, $subscribe = true) - { - $this->login(); - $this->_subscribeMailbox(Horde_Imap_Client_Mailbox::get($mailbox), (bool)$subscribe); - } - - /** - * Manage subscription status for a mailbox. - * - * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to [un]subscribe - * to. - * @param boolean $subscribe True to subscribe, false to - * unsubscribe. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _subscribeMailbox(Horde_Imap_Client_Mailbox $mailbox, - $subscribe); - - /** - * Obtain a list of mailboxes matching a pattern. - * - * @param mixed $pattern The mailbox search pattern(s) (see RFC 3501 - * [6.3.8] for the format). A UTF-8 string or an - * array of strings. If a Horde_Imap_Client_Mailbox - * object is given, it is escaped (i.e. wildcard - * patterns are converted to return the miminal - * number of matches possible). - * @param integer $mode Which mailboxes to return. Either: - * - Horde_Imap_Client::MBOX_SUBSCRIBED - * Return subscribed mailboxes. - * - Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS - * Return subscribed mailboxes that exist on the server. - * - Horde_Imap_Client::MBOX_UNSUBSCRIBED - * Return unsubscribed mailboxes. - * - Horde_Imap_Client::MBOX_ALL - * Return all mailboxes regardless of subscription status. - * - Horde_Imap_Client::MBOX_ALL_SUBSCRIBED (@since 2.23.0) - * Return all mailboxes regardless of subscription status, and ensure - * the '\subscribed' attribute is set if mailbox is subscribed - * (implies 'attributes' option is true). - * @param array $options Additional options: - *
-     *   - attributes: (boolean) If true, return attribute information under
-     *                 the 'attributes' key.
-     *                 DEFAULT: Do not return this information.
-     *   - children: (boolean) Tell server to return children attribute
-     *               information (\HasChildren, \HasNoChildren). Requires the
-     *               LIST-EXTENDED extension to guarantee this information is
-     *               returned. Server MAY return this attribute without this
-     *               option, or if the CHILDREN extension is available, but it
-     *               is not guaranteed.
-     *               DEFAULT: false
-     *   - flat: (boolean) If true, return a flat list of mailbox names only.
-     *           Overrides the 'attributes' option.
-     *           DEFAULT: Do not return flat list.
-     *   - recursivematch: (boolean) Force the server to return information
-     *                     about parent mailboxes that don't match other
-     *                     selection options, but have some sub-mailboxes that
-     *                     do. Information about children is returned in the
-     *                     CHILDINFO extended data item ('extended'). Requires
-     *                     the LIST-EXTENDED extension.
-     *                     DEFAULT: false
-     *   - remote: (boolean) Tell server to return mailboxes that reside on
-     *             another server. Requires the LIST-EXTENDED extension.
-     *             DEFAULT: false
-     *   - special_use: (boolean) Tell server to return special-use attribute
-     *                  information (see Horde_Imap_Client SPECIALUSE_*
-     *                  constants). Server must support the SPECIAL-USE return
-     *                  option for this setting to have any effect.
-     *                  DEFAULT: false
-     *   - status: (integer) Tell server to return status information. The
-     *             value is a bitmask that may contain any of:
-     *     - Horde_Imap_Client::STATUS_MESSAGES
-     *     - Horde_Imap_Client::STATUS_RECENT
-     *     - Horde_Imap_Client::STATUS_UIDNEXT
-     *     - Horde_Imap_Client::STATUS_UIDVALIDITY
-     *     - Horde_Imap_Client::STATUS_UNSEEN
-     *     - Horde_Imap_Client::STATUS_HIGHESTMODSEQ
-     *     DEFAULT: 0
-     *   - sort: (boolean) If true, return a sorted list of mailboxes?
-     *           DEFAULT: Do not sort the list.
-     *   - sort_delimiter: (string) If 'sort' is true, this is the delimiter
-     *                     used to sort the mailboxes.
-     *                     DEFAULT: '.'
-     * 
- * - * @return array If 'flat' option is true, the array values are a list - * of Horde_Imap_Client_Mailbox objects. Otherwise, the - * keys are UTF-8 mailbox names and the values are arrays - * with these keys: - * - attributes: (array) List of lower-cased attributes [only if - * 'attributes' option is true]. - * - delimiter: (string) The delimiter for the mailbox. - * - extended: (TODO) TODO [only if 'recursivematch' option is true and - * LIST-EXTENDED extension is supported on the server]. - * - mailbox: (Horde_Imap_Client_Mailbox) The mailbox object. - * - status: (array) See status() [only if 'status' option is true]. - * - * @throws Horde_Imap_Client_Exception - */ - public function listMailboxes($pattern, - $mode = Horde_Imap_Client::MBOX_ALL, - array $options = array()) - { - $this->login(); - - $pattern = is_array($pattern) - ? array_unique($pattern) - : array($pattern); - - /* Prepare patterns. */ - $plist = array(); - foreach ($pattern as $val) { - if ($val instanceof Horde_Imap_Client_Mailbox) { - $val = $val->list_escape; - } - $plist[] = Horde_Imap_Client_Mailbox::get(preg_replace( - array("/\*{2,}/", "/\%{2,}/"), - array('*', '%'), - Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($val) - ), true); - } - - if (isset($options['special_use']) && - !$this->_capability('SPECIAL-USE')) { - unset($options['special_use']); - } - - $ret = $this->_listMailboxes($plist, $mode, $options); - - if (!empty($options['status']) && - !$this->_capability('LIST-STATUS')) { - foreach ($this->status(array_keys($ret), $options['status']) as $key => $val) { - $ret[$key]['status'] = $val; - } - } - - if (empty($options['sort'])) { - return $ret; - } - - $list_ob = new Horde_Imap_Client_Mailbox_List(empty($options['flat']) ? array_keys($ret) : $ret); - $sorted = $list_ob->sort(array( - 'delimiter' => empty($options['sort_delimiter']) ? '.' : $options['sort_delimiter'] - )); - - if (!empty($options['flat'])) { - return $sorted; - } - - $out = array(); - foreach ($sorted as $val) { - $out[$val] = $ret[$val]; - } - - return $out; - } - - /** - * Obtain a list of mailboxes matching a pattern. - * - * @param array $pattern The mailbox search patterns - * (Horde_Imap_Client_Mailbox objects). - * @param integer $mode Which mailboxes to return. - * @param array $options Additional options. - * - * @return array See listMailboxes(). - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _listMailboxes($pattern, $mode, $options); - - /** - * Obtain status information for a mailbox. - * - * @param mixed $mailbox The mailbox(es) to query. Either a - * Horde_Imap_Client_Mailbox object, a string - * (UTF-8), or an array of objects/strings (since - * 2.10.0). - * @param integer $flags A bitmask of information requested from the - * server. Allowed flags: - *
-     *   - Horde_Imap_Client::STATUS_MESSAGES
-     *     Return key: messages
-     *     Return format: (integer) The number of messages in the mailbox.
-     *
-     *   - Horde_Imap_Client::STATUS_RECENT
-     *     Return key: recent
-     *     Return format: (integer) The number of messages with the \Recent
-     *                    flag set as currently reported in the mailbox
-     *
-     *   - Horde_Imap_Client::STATUS_RECENT_TOTAL
-     *     Return key: recent_total
-     *     Return format: (integer) The number of messages with the \Recent
-     *                    flag set. This returns the total number of messages
-     *                    that have been marked as recent in this mailbox
-     *                    since the PHP process began. (since 2.12.0)
-     *
-     *   - Horde_Imap_Client::STATUS_UIDNEXT
-     *     Return key: uidnext
-     *     Return format: (integer) The next UID to be assigned in the
-     *                    mailbox. Only returned if the server automatically
-     *                    provides the data.
-     *
-     *   - Horde_Imap_Client::STATUS_UIDNEXT_FORCE
-     *     Return key: uidnext
-     *     Return format: (integer) The next UID to be assigned in the
-     *                    mailbox. This option will always determine this
-     *                    value, even if the server does not automatically
-     *                    provide this data.
-     *
-     *   - Horde_Imap_Client::STATUS_UIDVALIDITY
-     *     Return key: uidvalidity
-     *     Return format: (integer) The unique identifier validity of the
-     *                    mailbox.
-     *
-     *   - Horde_Imap_Client::STATUS_UNSEEN
-     *     Return key: unseen
-     *     Return format: (integer) The number of messages which do not have
-     *                    the \Seen flag set.
-     *
-     *   - Horde_Imap_Client::STATUS_FIRSTUNSEEN
-     *     Return key: firstunseen
-     *     Return format: (integer) The sequence number of the first unseen
-     *                    message in the mailbox.
-     *
-     *   - Horde_Imap_Client::STATUS_FLAGS
-     *     Return key: flags
-     *     Return format: (array) The list of defined flags in the mailbox
-     *                    (all flags are in lowercase).
-     *
-     *   - Horde_Imap_Client::STATUS_PERMFLAGS
-     *     Return key: permflags
-     *     Return format: (array) The list of flags that a client can change
-     *                    permanently (all flags are in lowercase).
-     *
-     *   - Horde_Imap_Client::STATUS_HIGHESTMODSEQ
-     *     Return key: highestmodseq
-     *     Return format: (integer) If the server supports the CONDSTORE
-     *                    IMAP extension, this will be the highest
-     *                    mod-sequence value of all messages in the mailbox.
-     *                    Else 0 if CONDSTORE not available or the mailbox
-     *                    does not support mod-sequences.
-     *
-     *   - Horde_Imap_Client::STATUS_SYNCMODSEQ
-     *     Return key: syncmodseq
-     *     Return format: (integer) If caching, and the server supports the
-     *                    CONDSTORE IMAP extension, this is the cached
-     *                    mod-sequence value of the mailbox when it was opened
-     *                    for the first time in this access. Will be null if
-     *                    not caching, CONDSTORE not available, or the mailbox
-     *                    does not support mod-sequences.
-     *
-     *   - Horde_Imap_Client::STATUS_SYNCFLAGUIDS
-     *     Return key: syncflaguids
-     *     Return format: (Horde_Imap_Client_Ids) If caching, the server
-     *                    supports the CONDSTORE IMAP extension, and the
-     *                    mailbox contained cached data when opened for the
-     *                    first time in this access, this is the list of UIDs
-     *                    in which flags have changed since STATUS_SYNCMODSEQ.
-     *
-     *   - Horde_Imap_Client::STATUS_SYNCVANISHED
-     *     Return key: syncvanished
-     *     Return format: (Horde_Imap_Client_Ids) If caching, the server
-     *                    supports the CONDSTORE IMAP extension, and the
-     *                    mailbox contained cached data when opened for the
-     *                    first time in this access, this is the list of UIDs
-     *                    which have been deleted since STATUS_SYNCMODSEQ.
-     *
-     *   - Horde_Imap_Client::STATUS_UIDNOTSTICKY
-     *     Return key: uidnotsticky
-     *     Return format: (boolean) If the server supports the UIDPLUS IMAP
-     *                    extension, and the queried mailbox does not support
-     *                    persistent UIDs, this value will be true. In all
-     *                    other cases, this value will be false.
-     *
-     *   - Horde_Imap_Client::STATUS_FORCE_REFRESH
-     *     Normally, the status information will be cached for a given
-     *     mailbox. Since most PHP requests are generally less than a second,
-     *     this is fine. However, if your script is long running, the status
-     *     information may not be up-to-date. Specifying this flag will ensure
-     *     that the server is always polled for the current mailbox status
-     *     before results are returned. (since 2.14.0)
-     *
-     *   - Horde_Imap_Client::STATUS_ALL (DEFAULT)
-     *     Shortcut to return 'messages', 'recent', 'uidnext', 'uidvalidity',
-     *     and 'unseen' values.
-     * 
-     * @param array $opts     Additional options:
-     * 
-     *   - sort: (boolean) If true, sort the list of mailboxes? (since 2.10.0)
-     *           DEFAULT: Do not sort the list.
-     *   - sort_delimiter: (string) If 'sort' is true, this is the delimiter
-     *                     used to sort the mailboxes. (since 2.10.0)
-     *                     DEFAULT: '.'
-     * 
- * - * @return array If $mailbox contains multiple mailboxes, an array with - * keys being the UTF-8 mailbox name and values as arrays - * containing the requested keys (see above). - * Otherwise, an array with keys as the requested keys (see - * above) and values as the key data. - * - * @throws Horde_Imap_Client_Exception - */ - public function status($mailbox, $flags = Horde_Imap_Client::STATUS_ALL, - array $opts = array()) - { - $opts = array_merge(array( - 'sort' => false, - 'sort_delimiter' => '.' - ), $opts); - - $this->login(); - - if (is_array($mailbox)) { - if (empty($mailbox)) { - return array(); - } - $ret_array = true; - } else { - $mailbox = array($mailbox); - $ret_array = false; - } - - $mlist = array_map(array('Horde_Imap_Client_Mailbox', 'get'), $mailbox); - - $unselected_flags = array( - 'messages' => Horde_Imap_Client::STATUS_MESSAGES, - 'recent' => Horde_Imap_Client::STATUS_RECENT, - 'uidnext' => Horde_Imap_Client::STATUS_UIDNEXT, - 'uidvalidity' => Horde_Imap_Client::STATUS_UIDVALIDITY, - 'unseen' => Horde_Imap_Client::STATUS_UNSEEN - ); - - if (!$this->statuscache) { - $flags |= Horde_Imap_Client::STATUS_FORCE_REFRESH; - } - - if ($flags & Horde_Imap_Client::STATUS_ALL) { - foreach ($unselected_flags as $val) { - $flags |= $val; - } - } - - $master = $ret = array(); - - /* Catch flags that are not supported. */ - if (($flags & Horde_Imap_Client::STATUS_HIGHESTMODSEQ) && - !$this->_capability()->isEnabled('CONDSTORE')) { - $master['highestmodseq'] = 0; - $flags &= ~Horde_Imap_Client::STATUS_HIGHESTMODSEQ; - } - - if (($flags & Horde_Imap_Client::STATUS_UIDNOTSTICKY) && - !$this->_capability('UIDPLUS')) { - $master['uidnotsticky'] = false; - $flags &= ~Horde_Imap_Client::STATUS_UIDNOTSTICKY; - } - - /* UIDNEXT return options. */ - if ($flags & Horde_Imap_Client::STATUS_UIDNEXT_FORCE) { - $flags |= Horde_Imap_Client::STATUS_UIDNEXT; - } - - foreach ($mlist as $val) { - $name = strval($val); - $tmp_flags = $flags; - - if ($val->equals($this->_selected)) { - /* Check if already in mailbox. */ - $opened = true; - - if ($flags & Horde_Imap_Client::STATUS_FORCE_REFRESH) { - $this->noop(); - } - } else { - /* A list of STATUS options (other than those handled directly - * below) that require the mailbox to be explicitly opened. */ - $opened = ($flags & Horde_Imap_Client::STATUS_FIRSTUNSEEN) || - ($flags & Horde_Imap_Client::STATUS_FLAGS) || - ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) || - ($flags & Horde_Imap_Client::STATUS_UIDNOTSTICKY) || - /* Force mailboxes containing wildcards to be accessed via - * STATUS so that wildcards do not return a bunch of - * mailboxes in the LIST-STATUS response. */ - (strpbrk($name, '*%') !== false); - } - - $ret[$name] = $master; - $ptr = &$ret[$name]; - - /* STATUS_PERMFLAGS requires a read/write mailbox. */ - if ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) { - $this->openMailbox($val, Horde_Imap_Client::OPEN_READWRITE); - $opened = true; - } - - /* Handle SYNC related return options. These require the mailbox - * to be opened at least once. */ - if ($flags & Horde_Imap_Client::STATUS_SYNCMODSEQ) { - $this->openMailbox($val); - $ptr['syncmodseq'] = $this->_mailboxOb($val)->getStatus(Horde_Imap_Client::STATUS_SYNCMODSEQ); - $tmp_flags &= ~Horde_Imap_Client::STATUS_SYNCMODSEQ; - $opened = true; - } - - if ($flags & Horde_Imap_Client::STATUS_SYNCFLAGUIDS) { - $this->openMailbox($val); - $ptr['syncflaguids'] = $this->getIdsOb($this->_mailboxOb($val)->getStatus(Horde_Imap_Client::STATUS_SYNCFLAGUIDS)); - $tmp_flags &= ~Horde_Imap_Client::STATUS_SYNCFLAGUIDS; - $opened = true; - } - - if ($flags & Horde_Imap_Client::STATUS_SYNCVANISHED) { - $this->openMailbox($val); - $ptr['syncvanished'] = $this->getIdsOb($this->_mailboxOb($val)->getStatus(Horde_Imap_Client::STATUS_SYNCVANISHED)); - $tmp_flags &= ~Horde_Imap_Client::STATUS_SYNCVANISHED; - $opened = true; - } - - /* Handle RECENT_TOTAL option. */ - if ($flags & Horde_Imap_Client::STATUS_RECENT_TOTAL) { - $this->openMailbox($val); - $ptr['recent_total'] = $this->_mailboxOb($val)->getStatus(Horde_Imap_Client::STATUS_RECENT_TOTAL); - $tmp_flags &= ~Horde_Imap_Client::STATUS_RECENT_TOTAL; - $opened = true; - } - - if ($opened) { - if ($tmp_flags) { - $tmp = $this->_status(array($val), $tmp_flags); - $ptr += reset($tmp); - } - } else { - $to_process[] = $val; - } - } - - if ($flags && !empty($to_process)) { - if ((count($to_process) > 1) && - $this->_capability('LIST-STATUS')) { - foreach ($this->listMailboxes($to_process, Horde_Imap_Client::MBOX_ALL, array('status' => $flags)) as $key => $val) { - if (isset($val['status'])) { - $ret[$key] += $val['status']; - } - } - } else { - foreach ($this->_status($to_process, $flags) as $key => $val) { - $ret[$key] += $val; - } - } - } - - if (!$opts['sort'] || (count($ret) === 1)) { - return $ret_array - ? $ret - : reset($ret); - } - - $list_ob = new Horde_Imap_Client_Mailbox_List(array_keys($ret)); - $sorted = $list_ob->sort(array( - 'delimiter' => $opts['sort_delimiter'] - )); - - $out = array(); - foreach ($sorted as $val) { - $out[$val] = $ret[$val]; - } - - return $out; - } - - /** - * Obtain status information for mailboxes. - * - * @param array $mboxes The list of mailbox objects to query. - * @param integer $flags A bitmask of information requested from the - * server. - * - * @return array See array return for status(). - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _status($mboxes, $flags); - - /** - * Perform a STATUS call on multiple mailboxes at the same time. - * - * This method leverages the LIST-EXTENDED and LIST-STATUS extensions on - * the IMAP server to improve the efficiency of this operation. - * - * @deprecated Use status() instead. - * - * @param array $mailboxes The mailboxes to query. Either - * Horde_Imap_Client_Mailbox objects, strings - * (UTF-8), or a combination of the two. - * @param integer $flags See status(). - * @param array $opts Additional options: - * - sort: (boolean) If true, sort the list of mailboxes? - * DEFAULT: Do not sort the list. - * - sort_delimiter: (string) If 'sort' is true, this is the delimiter - * used to sort the mailboxes. - * DEFAULT: '.' - * - * @return array An array with the keys as the mailbox names (UTF-8) and - * the values as arrays with the requested keys (from the - * mask given in $flags). - */ - public function statusMultiple($mailboxes, - $flags = Horde_Imap_Client::STATUS_ALL, - array $opts = array()) - { - return $this->status($mailboxes, $flags, $opts); - } - - /** - * Append message(s) to a mailbox. - * - * @param mixed $mailbox The mailbox to append the message(s) to. Either - * a Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * @param array $data The message data to append, along with - * additional options. An array of arrays with - * each embedded array having the following - * entries: - *
-     *   - data: (mixed) The data to append. If a string or a stream resource,
-     *           this will be used as the entire contents of a single message.
-     *           If an array, will catenate all given parts into a single
-     *           message. This array contains one or more arrays with
-     *           two keys:
-     *     - t: (string) Either 'url' or 'text'.
-     *     - v: (mixed) If 't' is 'url', this is the IMAP URL to the message
-     *          part to append. If 't' is 'text', this is either a string or
-     *          resource representation of the message part data.
-     *     DEFAULT: NONE (entry is MANDATORY)
-     *   - flags: (array) An array of flags/keywords to set on the appended
-     *            message.
-     *            DEFAULT: Only the \Recent flag is set.
-     *   - internaldate: (DateTime) The internaldate to set for the appended
-     *                   message.
-     *                   DEFAULT: internaldate will be the same date as when
-     *                   the message was appended.
-     * 
- * @param array $options Additonal options: - *
-     *   - create: (boolean) Try to create $mailbox if it does not exist?
-     *             DEFAULT: No.
-     * 
- * - * @return Horde_Imap_Client_Ids The UIDs of the appended messages. - * - * @throws Horde_Imap_Client_Exception - */ - public function append($mailbox, $data, array $options = array()) - { - $this->login(); - - $mailbox = Horde_Imap_Client_Mailbox::get($mailbox); - - $ret = $this->_append($mailbox, $data, $options); - - if ($ret instanceof Horde_Imap_Client_Ids) { - return $ret; - } - - $uids = $this->getIdsOb(); - - foreach ($data as $val) { - if (is_resource($val['data'])) { - rewind($val['data']); - } - - $uids->add($this->_getUidByMessageId( - $mailbox, - Horde_Mime_Headers::parseHeaders($val['data'])->getHeader('Message-ID') - )); - } - - return $uids; - } - - /** - * Append message(s) to a mailbox. - * - * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to append the - * message(s) to. - * @param array $data The message data. - * @param array $options Additional options. - * - * @return mixed A Horde_Imap_Client_Ids object containing the UIDs of - * the appended messages (if server supports UIDPLUS - * extension) or true. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _append(Horde_Imap_Client_Mailbox $mailbox, - $data, $options); - - /** - * Request a checkpoint of the currently selected mailbox (RFC 3501 - * [6.4.1]). - * - * @throws Horde_Imap_Client_Exception - */ - public function check() - { - // CHECK only useful if we are already authenticated. - if ($this->_isAuthenticated) { - $this->_check(); - } - } - - /** - * Request a checkpoint of the currently selected mailbox. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _check(); - - /** - * Close the connection to the currently selected mailbox, optionally - * expunging all deleted messages (RFC 3501 [6.4.2]). - * - * @param array $options Additional options: - * - expunge: (boolean) Expunge all messages flagged as deleted? - * DEFAULT: No - * - * @throws Horde_Imap_Client_Exception - */ - public function close(array $options = array()) - { - // This check catches the non-logged in case. - if (is_null($this->_selected)) { - return; - } - - /* If we are caching, search for deleted messages. */ - if (!empty($options['expunge']) && $this->_initCache(true)) { - /* Make sure mailbox is read-write to expunge. */ - $this->openMailbox($this->_selected, Horde_Imap_Client::OPEN_READWRITE); - if ($this->_mode == Horde_Imap_Client::OPEN_READONLY) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Cannot expunge read-only mailbox."), - Horde_Imap_Client_Exception::MAILBOX_READONLY - ); - } - - $search_query = new Horde_Imap_Client_Search_Query(); - $search_query->flag(Horde_Imap_Client::FLAG_DELETED, true); - $search_res = $this->search($this->_selected, $search_query); - $mbox = $this->_selected; - } else { - $search_res = null; - } - - $this->_close($options); - $this->_selected = null; - $this->_mode = 0; - - if (!is_null($search_res)) { - $this->_deleteMsgs($mbox, $search_res['match']); - } - } - - /** - * Close the connection to the currently selected mailbox, optionally - * expunging all deleted messages (RFC 3501 [6.4.2]). - * - * @param array $options Additional options. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _close($options); - - /** - * Expunge deleted messages from the given mailbox. - * - * @param mixed $mailbox The mailbox to expunge. Either a - * Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * @param array $options Additional options: - * - delete: (boolean) If true, will flag all messages in 'ids' as - * deleted (since 2.10.0). - * DEFAULT: false - * - ids: (Horde_Imap_Client_Ids) A list of messages to expunge. These - * messages must already be flagged as deleted (unless 'delete' - * is true). - * DEFAULT: All messages marked as deleted will be expunged. - * - list: (boolean) If true, returns the list of expunged messages - * (UIDs only). - * DEFAULT: false - * - * @return Horde_Imap_Client_Ids If 'list' option is true, returns the - * UID list of expunged messages. - * - * @throws Horde_Imap_Client_Exception - */ - public function expunge($mailbox, array $options = array()) - { - // Open mailbox call will handle the login. - $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_READWRITE); - - /* Don't expunge if the mailbox is readonly. */ - if ($this->_mode == Horde_Imap_Client::OPEN_READONLY) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Cannot expunge read-only mailbox."), - Horde_Imap_Client_Exception::MAILBOX_READONLY - ); - } - - if (empty($options['ids'])) { - $options['ids'] = $this->getIdsOb(Horde_Imap_Client_Ids::ALL); - } elseif ($options['ids']->isEmpty()) { - return $this->getIdsOb(); - } - - return $this->_expunge($options); - } - - /** - * Expunge all deleted messages from the given mailbox. - * - * @param array $options Additional options. - * - * @return Horde_Imap_Client_Ids If 'list' option is true, returns the - * list of expunged messages. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _expunge($options); - - /** - * Search a mailbox. - * - * @param mixed $mailbox The mailbox to search. - * Either a - * Horde_Imap_Client_Mailbox - * object or a string - * (UTF-8). - * @param Horde_Imap_Client_Search_Query $query The search query. - * Defaults to an ALL - * search. - * @param array $options Additional options: - *
-     *   - nocache: (boolean) Don't cache the results.
-     *              DEFAULT: false (results cached, if possible)
-     *   - partial: (mixed) The range of results to return (message sequence
-     *              numbers) Only a single range is supported (represented by
-     *              the minimum and maximum values contained in the range
-     *              given).
-     *              DEFAULT: All messages are returned.
-     *   - results: (array) The data to return. Consists of zero or more of
-     *              the following flags:
-     *     - Horde_Imap_Client::SEARCH_RESULTS_COUNT
-     *     - Horde_Imap_Client::SEARCH_RESULTS_MATCH (DEFAULT)
-     *     - Horde_Imap_Client::SEARCH_RESULTS_MAX
-     *     - Horde_Imap_Client::SEARCH_RESULTS_MIN
-     *     - Horde_Imap_Client::SEARCH_RESULTS_SAVE
-     *     - Horde_Imap_Client::SEARCH_RESULTS_RELEVANCY
-     *   - sequence: (boolean) If true, returns an array of sequence numbers.
-     *               DEFAULT: Returns an array of UIDs
-     *   - sort: (array) Sort the returned list of messages. Multiple sort
-     *           criteria can be specified. Any sort criteria can be sorted in
-     *           reverse order (instead of the default ascending order) by
-     *           adding a Horde_Imap_Client::SORT_REVERSE element to the array
-     *           directly before adding the sort element. The following sort
-     *           criteria are available:
-     *     - Horde_Imap_Client::SORT_ARRIVAL
-     *     - Horde_Imap_Client::SORT_CC
-     *     - Horde_Imap_Client::SORT_DATE
-     *     - Horde_Imap_Client::SORT_DISPLAYFROM
-     *       On servers that don't support SORT=DISPLAY, this criteria will
-     *       fallback to doing client-side sorting.
-     *     - Horde_Imap_Client::SORT_DISPLAYFROM_FALLBACK
-     *       On servers that don't support SORT=DISPLAY, this criteria will
-     *       fallback to Horde_Imap_Client::SORT_FROM [since 2.4.0].
-     *     - Horde_Imap_Client::SORT_DISPLAYTO
-     *       On servers that don't support SORT=DISPLAY, this criteria will
-     *       fallback to doing client-side sorting.
-     *     - Horde_Imap_Client::SORT_DISPLAYTO_FALLBACK
-     *       On servers that don't support SORT=DISPLAY, this criteria will
-     *       fallback to Horde_Imap_Client::SORT_TO [since 2.4.0].
-     *     - Horde_Imap_Client::SORT_FROM
-     *     - Horde_Imap_Client::SORT_SEQUENCE
-     *     - Horde_Imap_Client::SORT_SIZE
-     *     - Horde_Imap_Client::SORT_SUBJECT
-     *     - Horde_Imap_Client::SORT_TO
-     *
-     *     [On servers that support SEARCH=FUZZY, this criteria is also
-     *     available:]
-     *     - Horde_Imap_Client::SORT_RELEVANCY
-     * 
- * - * @return array An array with the following keys: - *
-     *   - count: (integer) The number of messages that match the search
-     *            criteria. Always returned.
-     *   - match: (Horde_Imap_Client_Ids) The IDs that match $criteria, sorted
-     *            if the 'sort' modifier was set. Returned if
-     *            Horde_Imap_Client::SEARCH_RESULTS_MATCH is set.
-     *   - max: (integer) The UID (default) or message sequence number (if
-     *          'sequence' is true) of the highest message that satisifies
-     *          $criteria. Returns null if no matches found. Returned if
-     *          Horde_Imap_Client::SEARCH_RESULTS_MAX is set.
-     *   - min: (integer) The UID (default) or message sequence number (if
-     *          'sequence' is true) of the lowest message that satisifies
-     *          $criteria. Returns null if no matches found. Returned if
-     *          Horde_Imap_Client::SEARCH_RESULTS_MIN is set.
-     *   - modseq: (integer) The highest mod-sequence for all messages being
-     *            returned. Returned if 'sort' is false, the search query
-     *            includes a MODSEQ command, and the server supports the
-     *            CONDSTORE IMAP extension.
-     *   - relevancy: (array) The list of relevancy scores. Returned if
-     *                Horde_Imap_Client::SEARCH_RESULTS_RELEVANCY is set and
-     *                the server supports FUZZY search matching.
-     *   - save: (boolean) Whether the search results were saved. Returned if
-     *           Horde_Imap_Client::SEARCH_RESULTS_SAVE is set.
-     * 
- * - * @throws Horde_Imap_Client_Exception - */ - public function search($mailbox, $query = null, array $options = array()) - { - $this->login(); - - if (empty($options['results'])) { - $options['results'] = array( - Horde_Imap_Client::SEARCH_RESULTS_MATCH, - Horde_Imap_Client::SEARCH_RESULTS_COUNT - ); - } elseif (!in_array(Horde_Imap_Client::SEARCH_RESULTS_COUNT, $options['results'])) { - $options['results'][] = Horde_Imap_Client::SEARCH_RESULTS_COUNT; - } - - // Default to an ALL search. - if (is_null($query)) { - $query = new Horde_Imap_Client_Search_Query(); - } - - // Check for SEARCHRES support. - if ((($pos = array_search(Horde_Imap_Client::SEARCH_RESULTS_SAVE, $options['results'])) !== false) && - !$this->_capability('SEARCHRES')) { - unset($options['results'][$pos]); - } - - // Check for SORT-related options. - if (!empty($options['sort'])) { - foreach ($options['sort'] as $key => $val) { - switch ($val) { - case Horde_Imap_Client::SORT_DISPLAYFROM_FALLBACK: - $options['sort'][$key] = $this->_capability('SORT', 'DISPLAY') - ? Horde_Imap_Client::SORT_DISPLAYFROM - : Horde_Imap_Client::SORT_FROM; - break; - - case Horde_Imap_Client::SORT_DISPLAYTO_FALLBACK: - $options['sort'][$key] = $this->_capability('SORT', 'DISPLAY') - ? Horde_Imap_Client::SORT_DISPLAYTO - : Horde_Imap_Client::SORT_TO; - break; - } - } - } - - /* Default search results. */ - $default_ret = array( - 'count' => 0, - 'match' => $this->getIdsOb(), - 'max' => null, - 'min' => null, - 'relevancy' => array() - ); - - /* Build search query. */ - $squery = $query->build($this); - - /* Check for query contents. If empty, this means that the query - * object has identified that this query can NEVER return any results. - * Immediately return now. */ - if (!count($squery['query'])) { - return $default_ret; - } - - // Check for supported charset. - if (!is_null($squery['charset']) && - ($this->search_charset->query($squery['charset'], true) === false)) { - foreach ($this->search_charset->charsets as $val) { - try { - $new_query = clone $query; - $new_query->charset($val); - break; - } catch (Horde_Imap_Client_Exception_SearchCharset $e) { - unset($new_query); - } - } - - if (!isset($new_query)) { - throw $e; - } - - $query = $new_query; - $squery = $query->build($this); - } - - // Store query in $options array to pass to child method. - $options['_query'] = $squery; - - /* RFC 6203: MUST NOT request relevancy results if we are not using - * FUZZY searching. */ - if (in_array(Horde_Imap_Client::SEARCH_RESULTS_RELEVANCY, $options['results']) && - !in_array('SEARCH=FUZZY', $squery['exts_used'])) { - throw new InvalidArgumentException('Cannot specify RELEVANCY results if not doing a FUZZY search.'); - } - - /* Check for partial matching. */ - if (!empty($options['partial'])) { - $pids = $this->getIdsOb($options['partial'], true)->range_string; - if (!strlen($pids)) { - throw new InvalidArgumentException('Cannot specify empty sequence range for a PARTIAL search.'); - } - - if (strpos($pids, ':') === false) { - $pids .= ':' . $pids; - } - - $options['partial'] = $pids; - } - - /* Optimization - if query is just for a count of either RECENT or - * ALL messages, we can send status information instead. Can't - * optimize with unseen queries because we may cause an infinite loop - * between here and the status() call. */ - if ((count($options['results']) === 1) && - (reset($options['results']) == Horde_Imap_Client::SEARCH_RESULTS_COUNT)) { - switch ($squery['query']) { - case 'ALL': - $ret = $this->status($mailbox, Horde_Imap_Client::STATUS_MESSAGES); - return array('count' => $ret['messages']); - - case 'RECENT': - $ret = $this->status($mailbox, Horde_Imap_Client::STATUS_RECENT); - return array('count' => $ret['recent']); - } - } - - $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_AUTO); - - /* Take advantage of search result caching. If CONDSTORE available, - * we can cache all queries and invalidate the cache when the MODSEQ - * changes. If CONDSTORE not available, we can only store queries - * that don't involve flags. We store results by hashing the options - * array. */ - $cache = null; - if (empty($options['nocache']) && - $this->_initCache(true) && - ($this->_capability()->isEnabled('CONDSTORE') || - !$query->flagSearch())) { - $cache = $this->_getSearchCache('search', $options); - if (isset($cache['data'])) { - if (isset($cache['data']['match'])) { - $cache['data']['match'] = $this->getIdsOb($cache['data']['match']); - } - return $cache['data']; - } - } - - /* Optimization: Catch when there are no messages in a mailbox. */ - $status_res = $this->status($this->_selected, Horde_Imap_Client::STATUS_MESSAGES | Horde_Imap_Client::STATUS_HIGHESTMODSEQ); - if ($status_res['messages'] || - in_array(Horde_Imap_Client::SEARCH_RESULTS_SAVE, $options['results'])) { - /* RFC 7162 [3.1.2.2] - trying to do a MODSEQ SEARCH on a mailbox - * that doesn't support it will return BAD. */ - if (in_array('CONDSTORE', $squery['exts']) && - !$this->_mailboxOb()->getStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ)) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Mailbox does not support mod-sequences."), - Horde_Imap_Client_Exception::MBOXNOMODSEQ - ); - } - - $ret = $this->_search($query, $options); - } else { - $ret = $default_ret; - if (isset($status_res['highestmodseq'])) { - $ret['modseq'] = $status_res['highestmodseq']; - } - } - - if ($cache) { - $save = $ret; - if (isset($save['match'])) { - $save['match'] = strval($ret['match']); - } - $this->_setSearchCache($save, $cache); - } - - return $ret; - } - - /** - * Search a mailbox. - * - * @param object $query The search query. - * @param array $options Additional options. The '_query' key contains - * the value of $query->build(). - * - * @return Horde_Imap_Client_Ids An array of IDs. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _search($query, $options); - - /** - * Set the comparator to use for searching/sorting (RFC 5255). - * - * @param string $comparator The comparator string (see RFC 4790 [3.1] - - * "collation-id" - for format). The reserved - * string 'default' can be used to select - * the default comparator. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function setComparator($comparator = null) - { - $comp = is_null($comparator) - ? $this->getParam('comparator') - : $comparator; - if (is_null($comp)) { - return; - } - - $this->login(); - - if (!$this->_capability('I18NLEVEL', '2')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension( - 'I18NLEVEL', - 'The IMAP server does not support changing SEARCH/SORT comparators.' - ); - } - - $this->_setComparator($comp); - } - - /** - * Set the comparator to use for searching/sorting (RFC 5255). - * - * @param string $comparator The comparator string (see RFC 4790 [3.1] - - * "collation-id" - for format). The reserved - * string 'default' can be used to select - * the default comparator. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _setComparator($comparator); - - /** - * Get the comparator used for searching/sorting (RFC 5255). - * - * @return mixed Null if the default comparator is being used, or an - * array of comparator information (see RFC 5255 [4.8]). - * - * @throws Horde_Imap_Client_Exception - */ - public function getComparator() - { - $this->login(); - - return $this->_capability('I18NLEVEL', '2') - ? $this->_getComparator() - : null; - } - - /** - * Get the comparator used for searching/sorting (RFC 5255). - * - * @return mixed Null if the default comparator is being used, or an - * array of comparator information (see RFC 5255 [4.8]). - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _getComparator(); - - /** - * Thread sort a given list of messages (RFC 5256). - * - * @param mixed $mailbox The mailbox to query. Either a - * Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * @param array $options Additional options: - *
-     *   - criteria: (mixed) The following thread criteria are available:
-     *     - Horde_Imap_Client::THREAD_ORDEREDSUBJECT
-     *     - Horde_Imap_Client::THREAD_REFERENCES
-     *     - Horde_Imap_Client::THREAD_REFS
-     *       Other algorithms can be explicitly specified by passing the IMAP
-     *       thread algorithm in as a string value.
-     *     DEFAULT: Horde_Imap_Client::THREAD_ORDEREDSUBJECT
-     *   - search: (Horde_Imap_Client_Search_Query) The search query.
-     *             DEFAULT: All messages in mailbox included in thread sort.
-     *   - sequence: (boolean) If true, each message is stored and referred to
-     *               by its message sequence number.
-     *               DEFAULT: Stored/referred to by UID.
-     * 
- * - * @return Horde_Imap_Client_Data_Thread A thread data object. - * - * @throws Horde_Imap_Client_Exception - */ - public function thread($mailbox, array $options = array()) - { - // Open mailbox call will handle the login. - $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_AUTO); - - /* Take advantage of search result caching. If CONDSTORE available, - * we can cache all queries and invalidate the cache when the MODSEQ - * changes. If CONDSTORE not available, we can only store queries - * that don't involve flags. See search() for similar caching. */ - $cache = null; - if ($this->_initCache(true) && - ($this->_capability()->isEnabled('CONDSTORE') || - empty($options['search']) || - !$options['search']->flagSearch())) { - $cache = $this->_getSearchCache('thread', $options); - if (isset($cache['data']) && - ($cache['data'] instanceof Horde_Imap_Client_Data_Thread)) { - return $cache['data']; - } - } - - $status_res = $this->status($this->_selected, Horde_Imap_Client::STATUS_MESSAGES); - - $ob = $status_res['messages'] - ? $this->_thread($options) - : new Horde_Imap_Client_Data_Thread(array(), empty($options['sequence']) ? 'uid' : 'sequence'); - - if ($cache) { - $this->_setSearchCache($ob, $cache); - } - - return $ob; - } - - /** - * Thread sort a given list of messages (RFC 5256). - * - * @param array $options Additional options. See thread(). - * - * @return Horde_Imap_Client_Data_Thread A thread data object. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _thread($options); - - /** - * Fetch message data (see RFC 3501 [6.4.5]). - * - * @param mixed $mailbox The mailbox to search. - * Either a - * Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * @param Horde_Imap_Client_Fetch_Query $query Fetch query object. - * @param array $options Additional options: - * - changedsince: (integer) Only return messages that have a - * mod-sequence larger than this value. This option - * requires the CONDSTORE IMAP extension (if not present, - * this value is ignored). Additionally, the mailbox - * must support mod-sequences or an exception will be - * thrown. If valid, this option implicity adds the - * mod-sequence fetch criteria to the fetch command. - * DEFAULT: Mod-sequence values are ignored. - * - exists: (boolean) Ensure that all ids returned exist on the server. - * If false, the list of ids returned in the results object - * is not guaranteed to reflect the current state of the - * remote mailbox. - * DEFAULT: false - * - ids: (Horde_Imap_Client_Ids) A list of messages to fetch data from. - * DEFAULT: All messages in $mailbox will be fetched. - * - nocache: (boolean) If true, will not cache the results (previously - * cached data will still be used to generate results) [since - * 2.8.0]. - * DEFAULT: false - * - * @return Horde_Imap_Client_Fetch_Results A results object. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function fetch($mailbox, $query, array $options = array()) - { - try { - $ret = $this->_fetchWrapper($mailbox, $query, $options); - unset($this->_temp['fetch_nocache']); - return $ret; - } catch (Exception $e) { - unset($this->_temp['fetch_nocache']); - throw $e; - } - } - - /** - * Wrapper for fetch() to allow internal state to be reset on exception. - * - * @internal - * @see fetch() - */ - private function _fetchWrapper($mailbox, $query, $options) - { - $this->login(); - - $query = clone $query; - - $cache_array = $header_cache = $new_query = array(); - - if (empty($options['ids'])) { - $options['ids'] = $this->getIdsOb(Horde_Imap_Client_Ids::ALL); - } elseif ($options['ids']->isEmpty()) { - return new Horde_Imap_Client_Fetch_Results($this->_fetchDataClass); - } elseif ($options['ids']->search_res && - !$this->_capability('SEARCHRES')) { - /* SEARCHRES requires server support. */ - throw new Horde_Imap_Client_Exception_NoSupportExtension('SEARCHRES'); - } - - $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_AUTO); - $mbox_ob = $this->_mailboxOb(); - - if (!empty($options['nocache'])) { - $this->_temp['fetch_nocache'] = true; - } - - $cf = $this->_initCache(true) - ? $this->_cacheFields() - : array(); - - if (!empty($cf)) { - /* If using cache, we store by UID so we need to return UIDs. */ - $query->uid(); - } - - $modseq_check = !empty($options['changedsince']); - if ($query->contains(Horde_Imap_Client::FETCH_MODSEQ)) { - if (!$this->_capability()->isEnabled('CONDSTORE')) { - unset($query[Horde_Imap_Client::FETCH_MODSEQ]); - } elseif (empty($options['changedsince'])) { - $modseq_check = true; - } - } - - if ($modseq_check && - !$mbox_ob->getStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ)) { - /* RFC 7162 [3.1.2.2] - trying to do a MODSEQ FETCH on a mailbox - * that doesn't support it will return BAD. */ - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Mailbox does not support mod-sequences."), - Horde_Imap_Client_Exception::MBOXNOMODSEQ - ); - } - - /* Determine if caching is available and if anything in $query is - * cacheable. */ - foreach ($cf as $k => $v) { - if (isset($query[$k])) { - switch ($k) { - case Horde_Imap_Client::FETCH_ENVELOPE: - case Horde_Imap_Client::FETCH_FLAGS: - case Horde_Imap_Client::FETCH_IMAPDATE: - case Horde_Imap_Client::FETCH_SIZE: - case Horde_Imap_Client::FETCH_STRUCTURE: - $cache_array[$k] = $v; - break; - - case Horde_Imap_Client::FETCH_HEADERS: - $this->_temp['headers_caching'] = array(); - - foreach ($query[$k] as $key => $val) { - /* Only cache if directly requested. Iterate through - * requests to ensure at least one can be cached. */ - if (!empty($val['cache']) && !empty($val['peek'])) { - $cache_array[$k] = $v; - ksort($val); - $header_cache[$key] = hash('md5', serialize($val)); - } - } - break; - } - } - } - - $ret = new Horde_Imap_Client_Fetch_Results( - $this->_fetchDataClass, - $options['ids']->sequence ? Horde_Imap_Client_Fetch_Results::SEQUENCE : Horde_Imap_Client_Fetch_Results::UID - ); - - /* If nothing is cacheable, we can do a straight search. */ - if (empty($cache_array)) { - $options['_query'] = $query; - $this->_fetch($ret, array($options)); - return $ret; - } - - $cs_ret = empty($options['changedsince']) - ? null - : clone $ret; - - /* Convert special searches to UID lists and create mapping. */ - $ids = $this->resolveIds( - $this->_selected, - $options['ids'], - empty($options['exists']) ? 1 : 2 - ); - - /* Add non-user settable cache fields. */ - $cache_array[Horde_Imap_Client::FETCH_DOWNGRADED] = self::CACHE_DOWNGRADED; - - /* Get the cached values. */ - $data = $this->_cache->get( - $this->_selected, - $ids->ids, - array_values($cache_array), - $mbox_ob->getStatus(Horde_Imap_Client::STATUS_UIDVALIDITY) - ); - - /* Build a list of what we still need. */ - $map = array_flip($mbox_ob->map->map); - $sequence = $options['ids']->sequence; - foreach ($ids as $uid) { - $crit = clone $query; - - if ($sequence) { - if (!isset($map[$uid])) { - continue; - } - $entry_idx = $map[$uid]; - } else { - $entry_idx = $uid; - unset($crit[Horde_Imap_Client::FETCH_UID]); - } - - $entry = $ret->get($entry_idx); - - if (isset($map[$uid])) { - $entry->setSeq($map[$uid]); - unset($crit[Horde_Imap_Client::FETCH_SEQ]); - } - - $entry->setUid($uid); - - foreach ($cache_array as $key => $cid) { - switch ($key) { - case Horde_Imap_Client::FETCH_DOWNGRADED: - if (!empty($data[$uid][$cid])) { - $entry->setDowngraded(true); - } - break; - - case Horde_Imap_Client::FETCH_ENVELOPE: - if (isset($data[$uid][$cid]) && - ($data[$uid][$cid] instanceof Horde_Imap_Client_Data_Envelope)) { - $entry->setEnvelope($data[$uid][$cid]); - unset($crit[$key]); - } - break; - - case Horde_Imap_Client::FETCH_FLAGS: - if (isset($data[$uid][$cid]) && - is_array($data[$uid][$cid])) { - $entry->setFlags($data[$uid][$cid]); - unset($crit[$key]); - } - break; - - case Horde_Imap_Client::FETCH_HEADERS: - foreach ($header_cache as $hkey => $hval) { - if (isset($data[$uid][$cid][$hval])) { - /* We have found a cached entry with the same - * MD5 sum. */ - $entry->setHeaders($hkey, $data[$uid][$cid][$hval]); - $crit->remove($key, $hkey); - } else { - $this->_temp['headers_caching'][$hkey] = $hval; - } - } - break; - - case Horde_Imap_Client::FETCH_IMAPDATE: - if (isset($data[$uid][$cid]) && - ($data[$uid][$cid] instanceof Horde_Imap_Client_DateTime)) { - $entry->setImapDate($data[$uid][$cid]); - unset($crit[$key]); - } - break; - - case Horde_Imap_Client::FETCH_SIZE: - if (isset($data[$uid][$cid])) { - $entry->setSize($data[$uid][$cid]); - unset($crit[$key]); - } - break; - - case Horde_Imap_Client::FETCH_STRUCTURE: - if (isset($data[$uid][$cid]) && - ($data[$uid][$cid] instanceof Horde_Mime_Part)) { - $entry->setStructure($data[$uid][$cid]); - unset($crit[$key]); - } - break; - } - } - - if (count($crit)) { - $sig = $crit->hash(); - if (isset($new_query[$sig])) { - $new_query[$sig]['i'][] = $entry_idx; - } else { - $new_query[$sig] = array( - 'c' => $crit, - 'i' => array($entry_idx) - ); - } - } - } - - $to_fetch = array(); - foreach ($new_query as $val) { - $ids_ob = $this->getIdsOb(null, $sequence); - $ids_ob->duplicates = true; - $ids_ob->add($val['i']); - $to_fetch[] = array_merge($options, array( - '_query' => $val['c'], - 'ids' => $ids_ob - )); - } - - if (!empty($to_fetch)) { - $this->_fetch(is_null($cs_ret) ? $ret : $cs_ret, $to_fetch); - } - - if (is_null($cs_ret)) { - return $ret; - } - - /* If doing changedsince query, and all other data is cached, we still - * need to hit IMAP server to determine proper results set. */ - if (empty($new_query)) { - $squery = new Horde_Imap_Client_Search_Query(); - $squery->modseq($options['changedsince'] + 1); - $squery->ids($options['ids']); - - $cs = $this->search($this->_selected, $squery, array( - 'sequence' => $sequence - )); - - foreach ($cs['match'] as $val) { - $entry = $ret->get($val); - if ($sequence) { - $entry->setSeq($val); - } else { - $entry->setUid($val); - } - $cs_ret[$val] = $entry; - } - } else { - foreach ($cs_ret as $key => $val) { - $val->merge($ret->get($key)); - } - } - - return $cs_ret; - } - - /** - * Fetch message data. - * - * Fetch queries should be grouped in the $queries argument. Each value - * is an array of fetch options, with the fetch query stored in the - * '_query' parameter. IMPORTANT: All queries must have the same ID - * type (either sequence or UID). - * - * @param Horde_Imap_Client_Fetch_Results $results Fetch results. - * @param array $queries The list of queries. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _fetch(Horde_Imap_Client_Fetch_Results $results, - $queries); - - /** - * Get the list of vanished messages (UIDs that have been expunged since a - * given mod-sequence value). - * - * @param mixed $mailbox The mailbox to query. Either a - * Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * @param integer $modseq Search for expunged messages after this - * mod-sequence value. - * @param array $opts Additional options: - * - ids: (Horde_Imap_Client_Ids) Restrict to these UIDs. - * DEFAULT: Returns full list of UIDs vanished (QRESYNC only). - * This option is REQUIRED for non-QRESYNC servers or - * else an empty list will be returned. - * - * @return Horde_Imap_Client_Ids List of UIDs that have vanished. - * - * @throws Horde_Imap_Client_NoSupportExtension - */ - public function vanished($mailbox, $modseq, array $opts = array()) - { - $this->login(); - - if (empty($opts['ids'])) { - if (!$this->_capability()->isEnabled('QRESYNC')) { - return $this->getIdsOb(); - } - $opts['ids'] = $this->getIdsOb(Horde_Imap_Client_Ids::ALL); - } elseif ($opts['ids']->isEmpty()) { - return $this->getIdsOb(); - } elseif ($opts['ids']->sequence) { - throw new InvalidArgumentException('Vanished requires UIDs.'); - } - - $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_AUTO); - - if ($this->_capability()->isEnabled('QRESYNC')) { - if (!$this->_mailboxOb()->getStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ)) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Mailbox does not support mod-sequences."), - Horde_Imap_Client_Exception::MBOXNOMODSEQ - ); - } - - return $this->_vanished(max(1, $modseq), $opts['ids']); - } - - $ids = $this->resolveIds($mailbox, $opts['ids']); - - $squery = new Horde_Imap_Client_Search_Query(); - $squery->ids($ids); - $search = $this->search($mailbox, $squery, array( - 'nocache' => true - )); - - return $this->getIdsOb(array_diff($ids->ids, $search['match']->ids)); - } - - /** - * Get the list of vanished messages. - * - * @param integer $modseq Mod-sequence value. - * @param Horde_Imap_Client_Ids $ids UIDs. - * - * @return Horde_Imap_Client_Ids List of UIDs that have vanished. - */ - abstract protected function _vanished($modseq, Horde_Imap_Client_Ids $ids); - - /** - * Store message flag data (see RFC 3501 [6.4.6]). - * - * @param mixed $mailbox The mailbox containing the messages to modify. - * Either a Horde_Imap_Client_Mailbox object or a - * string (UTF-8). - * @param array $options Additional options: - * - add: (array) An array of flags to add. - * DEFAULT: No flags added. - * - ids: (Horde_Imap_Client_Ids) The list of messages to modify. - * DEFAULT: All messages in $mailbox will be modified. - * - remove: (array) An array of flags to remove. - * DEFAULT: No flags removed. - * - replace: (array) Replace the current flags with this set - * of flags. Overrides both the 'add' and 'remove' options. - * DEFAULT: No replace is performed. - * - unchangedsince: (integer) Only changes flags if the mod-sequence ID - * of the message is equal or less than this value. - * Requires the CONDSTORE IMAP extension on the server. - * Also requires the mailbox to support mod-sequences. - * Will throw an exception if either condition is not - * met. - * DEFAULT: mod-sequence is ignored when applying - * changes - * - * @return Horde_Imap_Client_Ids A Horde_Imap_Client_Ids object - * containing the list of IDs that failed - * the 'unchangedsince' test. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function store($mailbox, array $options = array()) - { - // Open mailbox call will handle the login. - $this->openMailbox($mailbox, Horde_Imap_Client::OPEN_READWRITE); - - /* SEARCHRES requires server support. */ - if (empty($options['ids'])) { - $options['ids'] = $this->getIdsOb(Horde_Imap_Client_Ids::ALL); - } elseif ($options['ids']->isEmpty()) { - return $this->getIdsOb(); - } elseif ($options['ids']->search_res && - !$this->_capability('SEARCHRES')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('SEARCHRES'); - } - - if (!empty($options['unchangedsince'])) { - if (!$this->_capability()->isEnabled('CONDSTORE')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('CONDSTORE'); - } - - /* RFC 7162 [3.1.2.2] - trying to do a UNCHANGEDSINCE STORE on a - * mailbox that doesn't support it will return BAD. */ - if (!$this->_mailboxOb()->getStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ)) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Mailbox does not support mod-sequences."), - Horde_Imap_Client_Exception::MBOXNOMODSEQ - ); - } - } - - return $this->_store($options); - } - - /** - * Store message flag data. - * - * @param array $options Additional options. - * - * @return Horde_Imap_Client_Ids A Horde_Imap_Client_Ids object - * containing the list of IDs that failed - * the 'unchangedsince' test. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _store($options); - - /** - * Copy messages to another mailbox. - * - * @param mixed $source The source mailbox. Either a - * Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * @param mixed $dest The destination mailbox. Either a - * Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * @param array $options Additional options: - * - create: (boolean) Try to create $dest if it does not exist? - * DEFAULT: No. - * - force_map: (boolean) Forces the array mapping to always be - * returned. [@since 2.19.0] - * - ids: (Horde_Imap_Client_Ids) The list of messages to copy. - * DEFAULT: All messages in $mailbox will be copied. - * - move: (boolean) If true, delete the original messages. - * DEFAULT: Original messages are not deleted. - * - * @return mixed An array mapping old UIDs (keys) to new UIDs (values) on - * success (only guaranteed if 'force_map' is true) or - * true. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function copy($source, $dest, array $options = array()) - { - // Open mailbox call will handle the login. - $this->openMailbox($source, empty($options['move']) ? Horde_Imap_Client::OPEN_AUTO : Horde_Imap_Client::OPEN_READWRITE); - - /* SEARCHRES requires server support. */ - if (empty($options['ids'])) { - $options['ids'] = $this->getIdsOb(Horde_Imap_Client_Ids::ALL); - } elseif ($options['ids']->isEmpty()) { - return array(); - } elseif ($options['ids']->search_res && - !$this->_capability('SEARCHRES')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('SEARCHRES'); - } - - $dest = Horde_Imap_Client_Mailbox::get($dest); - $res = $this->_copy($dest, $options); - - if (($res === true) && !empty($options['force_map'])) { - /* Need to manually create mapping from Message-ID data. */ - $query = new Horde_Imap_Client_Fetch_Query(); - $query->envelope(); - $fetch = $this->fetch($source, $query, array( - 'ids' => $options['ids'] - )); - - $res = array(); - foreach ($fetch as $val) { - if ($uid = $this->_getUidByMessageId($dest, $val->getEnvelope()->message_id)) { - $res[$val->getUid()] = $uid; - } - } - } - - return $res; - } - - /** - * Copy messages to another mailbox. - * - * @param Horde_Imap_Client_Mailbox $dest The destination mailbox. - * @param array $options Additional options. - * - * @return mixed An array mapping old UIDs (keys) to new UIDs (values) on - * success (if the IMAP server and/or driver support the - * UIDPLUS extension) or true. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _copy(Horde_Imap_Client_Mailbox $dest, - $options); - - /** - * Set quota limits. The server must support the IMAP QUOTA extension - * (RFC 2087). - * - * @param mixed $root The quota root. Either a - * Horde_Imap_Client_Mailbox object or a string - * (UTF-8). - * @param array $resources The resource values to set. Keys are the - * resource atom name; value is the resource - * value. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function setQuota($root, array $resources = array()) - { - $this->login(); - - if (!$this->_capability('QUOTA')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('QUOTA'); - } - - if (!empty($resources)) { - $this->_setQuota(Horde_Imap_Client_Mailbox::get($root), $resources); - } - } - - /** - * Set quota limits. - * - * @param Horde_Imap_Client_Mailbox $root The quota root. - * @param array $resources The resource values to set. - * - * @return boolean True on success. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _setQuota(Horde_Imap_Client_Mailbox $root, - $resources); - - /** - * Get quota limits. The server must support the IMAP QUOTA extension - * (RFC 2087). - * - * @param mixed $root The quota root. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * - * @return mixed An array with resource keys. Each key holds an array - * with 2 values: 'limit' and 'usage'. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function getQuota($root) - { - $this->login(); - - if (!$this->_capability('QUOTA')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('QUOTA'); - } - - return $this->_getQuota(Horde_Imap_Client_Mailbox::get($root)); - } - - /** - * Get quota limits. - * - * @param Horde_Imap_Client_Mailbox $root The quota root. - * - * @return mixed An array with resource keys. Each key holds an array - * with 2 values: 'limit' and 'usage'. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _getQuota(Horde_Imap_Client_Mailbox $root); - - /** - * Get quota limits for a mailbox. The server must support the IMAP QUOTA - * extension (RFC 2087). - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * - * @return mixed An array with the keys being the quota roots. Each key - * holds an array with resource keys: each of these keys - * holds an array with 2 values: 'limit' and 'usage'. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function getQuotaRoot($mailbox) - { - $this->login(); - - if (!$this->_capability('QUOTA')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('QUOTA'); - } - - return $this->_getQuotaRoot(Horde_Imap_Client_Mailbox::get($mailbox)); - } - - /** - * Get quota limits for a mailbox. - * - * @param Horde_Imap_Client_Mailbox $mailbox A mailbox. - * - * @return mixed An array with the keys being the quota roots. Each key - * holds an array with resource keys: each of these keys - * holds an array with 2 values: 'limit' and 'usage'. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _getQuotaRoot(Horde_Imap_Client_Mailbox $mailbox); - - /** - * Get the ACL rights for a given mailbox. The server must support the - * IMAP ACL extension (RFC 2086/4314). - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * - * @return array An array with identifiers as the keys and - * Horde_Imap_Client_Data_Acl objects as the values. - * - * @throws Horde_Imap_Client_Exception - */ - public function getACL($mailbox) - { - $this->login(); - return $this->_getACL(Horde_Imap_Client_Mailbox::get($mailbox)); - } - - /** - * Get ACL rights for a given mailbox. - * - * @param Horde_Imap_Client_Mailbox $mailbox A mailbox. - * - * @return array An array with identifiers as the keys and - * Horde_Imap_Client_Data_Acl objects as the values. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _getACL(Horde_Imap_Client_Mailbox $mailbox); - - /** - * Set ACL rights for a given mailbox/identifier. - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * @param string $identifier The identifier to alter (UTF-8). - * @param array $options Additional options: - * - rights: (string) The rights to alter or set. - * - action: (string, optional) If 'add' or 'remove', adds or removes the - * specified rights. Sets the rights otherwise. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function setACL($mailbox, $identifier, $options) - { - $this->login(); - - if (!$this->_capability('ACL')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('ACL'); - } - - if (empty($options['rights'])) { - if (!isset($options['action']) || - (($options['action'] != 'add') && - $options['action'] != 'remove')) { - $this->_deleteACL( - Horde_Imap_Client_Mailbox::get($mailbox), - Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($identifier) - ); - } - return; - } - - $acl = ($options['rights'] instanceof Horde_Imap_Client_Data_Acl) - ? $options['rights'] - : new Horde_Imap_Client_Data_Acl(strval($options['rights'])); - - $options['rights'] = $acl->getString( - $this->_capability('RIGHTS') - ? Horde_Imap_Client_Data_AclCommon::RFC_4314 - : Horde_Imap_Client_Data_AclCommon::RFC_2086 - ); - if (isset($options['action'])) { - switch ($options['action']) { - case 'add': - $options['rights'] = '+' . $options['rights']; - break; - case 'remove': - $options['rights'] = '-' . $options['rights']; - break; - } - } - - $this->_setACL( - Horde_Imap_Client_Mailbox::get($mailbox), - Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($identifier), - $options - ); - } - - /** - * Set ACL rights for a given mailbox/identifier. - * - * @param Horde_Imap_Client_Mailbox $mailbox A mailbox. - * @param string $identifier The identifier to alter - * (UTF7-IMAP). - * @param array $options Additional options. 'rights' - * contains the string of - * rights to set on the server. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _setACL(Horde_Imap_Client_Mailbox $mailbox, - $identifier, $options); - - /** - * Deletes ACL rights for a given mailbox/identifier. - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * @param string $identifier The identifier to delete (UTF-8). - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function deleteACL($mailbox, $identifier) - { - $this->login(); - - if (!$this->_capability('ACL')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('ACL'); - } - - $this->_deleteACL( - Horde_Imap_Client_Mailbox::get($mailbox), - Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($identifier) - ); - } - - /** - * Deletes ACL rights for a given mailbox/identifier. - * - * @param Horde_Imap_Client_Mailbox $mailbox A mailbox. - * @param string $identifier The identifier to delete - * (UTF7-IMAP). - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _deleteACL(Horde_Imap_Client_Mailbox $mailbox, - $identifier); - - /** - * List the ACL rights for a given mailbox/identifier. The server must - * support the IMAP ACL extension (RFC 2086/4314). - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * @param string $identifier The identifier to query (UTF-8). - * - * @return Horde_Imap_Client_Data_AclRights An ACL data rights object. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function listACLRights($mailbox, $identifier) - { - $this->login(); - - if (!$this->_capability('ACL')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('ACL'); - } - - return $this->_listACLRights( - Horde_Imap_Client_Mailbox::get($mailbox), - Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($identifier) - ); - } - - /** - * Get ACL rights for a given mailbox/identifier. - * - * @param Horde_Imap_Client_Mailbox $mailbox A mailbox. - * @param string $identifier The identifier to query - * (UTF7-IMAP). - * - * @return Horde_Imap_Client_Data_AclRights An ACL data rights object. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _listACLRights(Horde_Imap_Client_Mailbox $mailbox, - $identifier); - - /** - * Get the ACL rights for the current user for a given mailbox. The - * server must support the IMAP ACL extension (RFC 2086/4314). - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * - * @return Horde_Imap_Client_Data_Acl An ACL data object. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function getMyACLRights($mailbox) - { - $this->login(); - - if (!$this->_capability('ACL')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('ACL'); - } - - return $this->_getMyACLRights(Horde_Imap_Client_Mailbox::get($mailbox)); - } - - /** - * Get the ACL rights for the current user for a given mailbox. - * - * @param Horde_Imap_Client_Mailbox $mailbox A mailbox. - * - * @return Horde_Imap_Client_Data_Acl An ACL data object. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _getMyACLRights(Horde_Imap_Client_Mailbox $mailbox); - - /** - * Return master list of ACL rights available on the server. - * - * @return array A list of ACL rights. - */ - public function allAclRights() - { - $this->login(); - - $rights = array( - Horde_Imap_Client::ACL_LOOKUP, - Horde_Imap_Client::ACL_READ, - Horde_Imap_Client::ACL_SEEN, - Horde_Imap_Client::ACL_WRITE, - Horde_Imap_Client::ACL_INSERT, - Horde_Imap_Client::ACL_POST, - Horde_Imap_Client::ACL_ADMINISTER - ); - - if ($capability = $this->_capability()->getParams('RIGHTS')) { - // Add rights defined in CAPABILITY string (RFC 4314). - return array_merge($rights, str_split(reset($capability))); - } - - // Add RFC 2086 rights (deprecated by RFC 4314, but need to keep for - // compatibility with old servers). - return array_merge($rights, array( - Horde_Imap_Client::ACL_CREATE, - Horde_Imap_Client::ACL_DELETE - )); - } - - /** - * Get metadata for a given mailbox. The server must support either the - * IMAP METADATA extension (RFC 5464) or the ANNOTATEMORE extension - * (http://ietfreport.isoc.org/idref/draft-daboo-imap-annotatemore/). - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * @param array $entries The entries to fetch (UTF-8 strings). - * @param array $options Additional options: - * - depth: (string) Either "0", "1" or "infinity". Returns only the - * given value (0), only values one level below the specified - * value (1) or all entries below the specified value - * (infinity). - * - maxsize: (integer) The maximal size the returned values may have. - * DEFAULT: No maximal size. - * - * @return array An array with metadata names as the keys and metadata - * values as the values. If 'maxsize' is set, and entries - * exist on the server larger than this size, the size will - * be returned in the key '*longentries'. - * - * @throws Horde_Imap_Client_Exception - */ - public function getMetadata($mailbox, $entries, array $options = array()) - { - $this->login(); - - if (!is_array($entries)) { - $entries = array($entries); - } - - return $this->_getMetadata(Horde_Imap_Client_Mailbox::get($mailbox), array_map(array('Horde_Imap_Client_Utf7imap', 'Utf8ToUtf7Imap'), $entries), $options); - } - - /** - * Get metadata for a given mailbox. - * - * @param Horde_Imap_Client_Mailbox $mailbox A mailbox. - * @param array $entries The entries to fetch - * (UTF7-IMAP strings). - * @param array $options Additional options. - * - * @return array An array with metadata names as the keys and metadata - * values as the values. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _getMetadata(Horde_Imap_Client_Mailbox $mailbox, - $entries, $options); - - /** - * Set metadata for a given mailbox/identifier. - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). If empty, sets a - * server annotation. - * @param array $data A set of data values. The metadata values - * corresponding to the keys of the array will - * be set to the values in the array. - * - * @throws Horde_Imap_Client_Exception - */ - public function setMetadata($mailbox, $data) - { - $this->login(); - $this->_setMetadata(Horde_Imap_Client_Mailbox::get($mailbox), $data); - } - - /** - * Set metadata for a given mailbox/identifier. - * - * @param Horde_Imap_Client_Mailbox $mailbox A mailbox. - * @param array $data A set of data values. See - * setMetadata() for format. - * - * @throws Horde_Imap_Client_Exception - */ - abstract protected function _setMetadata(Horde_Imap_Client_Mailbox $mailbox, - $data); - - /* Public utility functions. */ - - /** - * Returns a unique identifier for the current mailbox status. - * - * @deprecated - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * @param array $addl Additional cache info to add to the cache ID - * string. - * - * @return string The cache ID string, which will change when the - * composition of the mailbox changes. The uidvalidity - * will always be the first element, and will be delimited - * by the '|' character. - * - * @throws Horde_Imap_Client_Exception - */ - public function getCacheId($mailbox, array $addl = array()) - { - return Horde_Imap_Client_Base_Deprecated::getCacheId($this, $mailbox, $this->_capability()->isEnabled('CONDSTORE'), $addl); - } - - /** - * Parses a cacheID created by getCacheId(). - * - * @deprecated - * - * @param string $id The cache ID. - * - * @return array An array with the following information: - * - highestmodseq: (integer) - * - messages: (integer) - * - uidnext: (integer) - * - uidvalidity: (integer) Always present - */ - public function parseCacheId($id) - { - return Horde_Imap_Client_Base_Deprecated::parseCacheId($id); - } - - /** - * Resolves an IDs object into a list of IDs. - * - * @param Horde_Imap_Client_Mailbox $mailbox The mailbox. - * @param Horde_Imap_Client_Ids $ids The Ids object. - * @param integer $convert Convert to UIDs? - * - 0: No - * - 1: Only if $ids is not already a UIDs object - * - 2: Always - * - * @return Horde_Imap_Client_Ids The list of IDs. - */ - public function resolveIds(Horde_Imap_Client_Mailbox $mailbox, - Horde_Imap_Client_Ids $ids, $convert = 0) - { - $map = $this->_mailboxOb($mailbox)->map; - - if ($ids->special) { - /* Optimization for ALL sequence searches. */ - if (!$convert && $ids->all && $ids->sequence) { - $res = $this->status($mailbox, Horde_Imap_Client::STATUS_MESSAGES); - return $this->getIdsOb($res['messages'] ? ('1:' . $res['messages']) : array(), true); - } - - $convert = 2; - } elseif (!$convert || - (!$ids->sequence && ($convert == 1)) || - $ids->isEmpty()) { - return clone $ids; - } else { - /* Do an all or nothing: either we have all the numbers/UIDs in - * memory and can return, or just send the whole ID query to the - * server. Any advantage we would get by a partial search are - * outweighed by the complexities needed to make the search and - * then merge back into the original results. */ - $lookup = $map->lookup($ids); - if (count($lookup) === count($ids)) { - return $this->getIdsOb(array_values($lookup)); - } - } - - $query = new Horde_Imap_Client_Search_Query(); - $query->ids($ids); - - $res = $this->search($mailbox, $query, array( - 'results' => array( - Horde_Imap_Client::SEARCH_RESULTS_MATCH, - Horde_Imap_Client::SEARCH_RESULTS_SAVE - ), - 'sequence' => (!$convert && $ids->sequence), - 'sort' => array(Horde_Imap_Client::SORT_SEQUENCE) - )); - - /* Update mapping. */ - if ($convert) { - if ($ids->all) { - $ids = $this->getIdsOb('1:' . count($res['match'])); - } elseif ($ids->special) { - return $res['match']; - } - - /* Sanity checking (Bug #12911). */ - $list1 = array_slice($ids->ids, 0, count($res['match'])); - $list2 = $res['match']->ids; - if (!empty($list1) && - !empty($list2) && - (count($list1) === count($list2))) { - $map->update(array_combine($list1, $list2)); - } - } - - return $res['match']; - } - - /** - * Determines if the given charset is valid for search-related queries. - * This check pertains just to the basic IMAP SEARCH command. - * - * @deprecated Use $search_charset property instead. - * - * @param string $charset The query charset. - * - * @return boolean True if server supports this charset. - */ - public function validSearchCharset($charset) - { - return $this->search_charset->query($charset); - } - - /* Mailbox syncing functions. */ - - /** - * Returns a unique token for the current mailbox synchronization status. - * - * @since 2.2.0 - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * - * @return string The sync token. - * - * @throws Horde_Imap_Client_Exception - */ - public function getSyncToken($mailbox) - { - $out = array(); - - foreach ($this->_syncStatus($mailbox) as $key => $val) { - $out[] = $key . $val; - } - - return base64_encode(implode(',', $out)); - } - - /** - * Synchronize a mailbox from a sync token. - * - * @since 2.2.0 - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * @param string $token A sync token generated by getSyncToken(). - * @param array $opts Additional options: - * - criteria: (integer) Mask of Horde_Imap_Client::SYNC_* criteria to - * return. Defaults to SYNC_ALL. - * - ids: (Horde_Imap_Client_Ids) A cached list of UIDs. Unless QRESYNC - * is available on the server, failure to specify this option - * means SYNC_VANISHEDUIDS information cannot be returned. - * - * @return Horde_Imap_Client_Data_Sync A sync object. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_Sync - */ - public function sync($mailbox, $token, array $opts = array()) - { - if (($token = base64_decode($token, true)) === false) { - throw new Horde_Imap_Client_Exception_Sync('Bad token.', Horde_Imap_Client_Exception_Sync::BAD_TOKEN); - } - - $sync = array(); - foreach (explode(',', $token) as $val) { - $sync[substr($val, 0, 1)] = substr($val, 1); - } - - return new Horde_Imap_Client_Data_Sync( - $this, - $mailbox, - $sync, - $this->_syncStatus($mailbox), - (isset($opts['criteria']) ? $opts['criteria'] : Horde_Imap_Client::SYNC_ALL), - (isset($opts['ids']) ? $opts['ids'] : null) - ); - } - - /* Private utility functions. */ - - /** - * Store FETCH data in cache. - * - * @param Horde_Imap_Client_Fetch_Results $data The fetch results. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _updateCache(Horde_Imap_Client_Fetch_Results $data) - { - if (!empty($this->_temp['fetch_nocache']) || - empty($this->_selected) || - !count($data) || - !$this->_initCache(true)) { - return; - } - - $c = $this->getParam('cache'); - if (in_array(strval($this->_selected), $c['fetch_ignore'])) { - $this->_debug->info(sprintf( - 'CACHE: Ignoring FETCH data [%s]', - $this->_selected - )); - return; - } - - /* Optimization: we can directly use getStatus() here since we know - * these values are initialized. */ - $mbox_ob = $this->_mailboxOb(); - $highestmodseq = $mbox_ob->getStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ); - $uidvalidity = $mbox_ob->getStatus(Horde_Imap_Client::STATUS_UIDVALIDITY); - - $mapping = $modseq = $tocache = array(); - if (count($data)) { - $cf = $this->_cacheFields(); - } - - foreach ($data as $v) { - /* It is possible that we received FETCH information that doesn't - * contain UID data. This is uncacheable so don't process. */ - if (!($uid = $v->getUid())) { - return; - } - - $tmp = array(); - - if ($v->isDowngraded()) { - $tmp[self::CACHE_DOWNGRADED] = true; - } - - foreach ($cf as $key => $val) { - if ($v->exists($key)) { - switch ($key) { - case Horde_Imap_Client::FETCH_ENVELOPE: - $tmp[$val] = $v->getEnvelope(); - break; - - case Horde_Imap_Client::FETCH_FLAGS: - if ($highestmodseq) { - $modseq[$uid] = $v->getModSeq(); - $tmp[$val] = $v->getFlags(); - } - break; - - case Horde_Imap_Client::FETCH_HEADERS: - foreach ($this->_temp['headers_caching'] as $label => $hash) { - if ($hdr = $v->getHeaders($label)) { - $tmp[$val][$hash] = $hdr; - } - } - break; - - case Horde_Imap_Client::FETCH_IMAPDATE: - $tmp[$val] = $v->getImapDate(); - break; - - case Horde_Imap_Client::FETCH_SIZE: - $tmp[$val] = $v->getSize(); - break; - - case Horde_Imap_Client::FETCH_STRUCTURE: - $tmp[$val] = clone $v->getStructure(); - break; - } - } - } - - if (!empty($tmp)) { - $tocache[$uid] = $tmp; - } - - $mapping[$v->getSeq()] = $uid; - } - - if (!empty($mapping)) { - if (!empty($tocache)) { - $this->_cache->set($this->_selected, $tocache, $uidvalidity); - } - - $this->_mailboxOb()->map->update($mapping); - } - - if (!empty($modseq)) { - $this->_updateModSeq(max(array_merge($modseq, array($highestmodseq)))); - $mbox_ob->setStatus(Horde_Imap_Client::STATUS_SYNCFLAGUIDS, array_keys($modseq)); - } - } - - /** - * Moves cache entries from the current mailbox to another mailbox. - * - * @param Horde_Imap_Client_Mailbox $to The destination mailbox. - * @param array $map Mapping of source UIDs (keys) to - * destination UIDs (values). - * @param string $uidvalid UIDVALIDITY of destination - * mailbox. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _moveCache(Horde_Imap_Client_Mailbox $to, $map, - $uidvalid) - { - if (!$this->_initCache()) { - return; - } - - $c = $this->getParam('cache'); - if (in_array(strval($to), $c['fetch_ignore'])) { - $this->_debug->info(sprintf( - 'CACHE: Ignoring moving FETCH data (%s => %s)', - $this->_selected, - $to - )); - return; - } - - $old = $this->_cache->get($this->_selected, array_keys($map), null); - $new = array(); - - foreach ($map as $key => $val) { - if (!empty($old[$key])) { - $new[$val] = $old[$key]; - } - } - - if (!empty($new)) { - $this->_cache->set($to, $new, $uidvalid); - } - } - - /** - * Delete messages in the cache. - * - * @param Horde_Imap_Client_Mailbox $mailbox The mailbox. - * @param Horde_Imap_Client_Ids $ids The list of IDs to delete in - * $mailbox. - * @param array $opts Additional options (not used - * in base class). - * - * @return Horde_Imap_Client_Ids UIDs that were deleted. - * @throws Horde_Imap_Client_Exception - */ - protected function _deleteMsgs(Horde_Imap_Client_Mailbox $mailbox, - Horde_Imap_Client_Ids $ids, - array $opts = array()) - { - if (!$this->_initCache()) { - return $ids; - } - - $mbox_ob = $this->_mailboxOb(); - $ids_ob = $ids->sequence - ? $this->getIdsOb($mbox_ob->map->lookup($ids)) - : $ids; - - $this->_cache->deleteMsgs($mailbox, $ids_ob->ids); - $mbox_ob->setStatus(Horde_Imap_Client::STATUS_SYNCVANISHED, $ids_ob->ids); - $mbox_ob->map->remove($ids); - - return $ids_ob; - } - - /** - * Retrieve data from the search cache. - * - * @param string $type The cache type ('search' or 'thread'). - * @param array $options The options array of the calling function. - * - * @return mixed Returns search cache metadata. If search was retrieved, - * data is in key 'data'. - * Returns null if caching is not available. - */ - protected function _getSearchCache($type, $options) - { - $status = $this->status($this->_selected, Horde_Imap_Client::STATUS_HIGHESTMODSEQ | Horde_Imap_Client::STATUS_UIDVALIDITY); - - /* Search caching requires MODSEQ, which may not be active for a - * mailbox. */ - if (empty($status['highestmodseq'])) { - return null; - } - - ksort($options); - $cache = hash('md5', $type . serialize($options)); - $cacheid = $this->getSyncToken($this->_selected); - $ret = array(); - - $md = $this->_cache->getMetaData( - $this->_selected, - $status['uidvalidity'], - array(self::CACHE_SEARCH, self::CACHE_SEARCHID) - ); - - if (!isset($md[self::CACHE_SEARCHID]) || - ($md[self::CACHE_SEARCHID] != $cacheid)) { - $md[self::CACHE_SEARCH] = array(); - $md[self::CACHE_SEARCHID] = $cacheid; - if ($this->_debug->debug && - !isset($this->_temp['searchcacheexpire'][strval($this->_selected)])) { - $this->_debug->info(sprintf( - 'SEARCH: Expired from cache [%s]', - $this->_selected - )); - $this->_temp['searchcacheexpire'][strval($this->_selected)] = true; - } - } elseif (isset($md[self::CACHE_SEARCH][$cache])) { - $this->_debug->info(sprintf( - 'SEARCH: Retrieved %s from cache (%s [%s])', - $type, - $cache, - $this->_selected - )); - $ret['data'] = $md[self::CACHE_SEARCH][$cache]; - unset($md[self::CACHE_SEARCHID]); - } - - return array_merge($ret, array( - 'id' => $cache, - 'metadata' => $md, - 'type' => $type - )); - } - - /** - * Set data in the search cache. - * - * @param mixed $data The cache data to store. - * @param string $sdata The search data returned from _getSearchCache(). - */ - protected function _setSearchCache($data, $sdata) - { - $sdata['metadata'][self::CACHE_SEARCH][$sdata['id']] = $data; - - $this->_cache->setMetaData($this->_selected, null, $sdata['metadata']); - - if ($this->_debug->debug) { - $this->_debug->info(sprintf( - 'SEARCH: Saved %s to cache (%s [%s])', - $sdata['type'], - $sdata['id'], - $this->_selected - )); - unset($this->_temp['searchcacheexpire'][strval($this->_selected)]); - } - } - - /** - * Updates the cached MODSEQ value. - * - * @param integer $modseq MODSEQ value to store. - * - * @return mixed The MODSEQ of the old value if it was replaced (or false - * if it didn't exist or is the same). - */ - protected function _updateModSeq($modseq) - { - if (!$this->_initCache(true)) { - return false; - } - - $mbox_ob = $this->_mailboxOb(); - $uidvalid = $mbox_ob->getStatus(Horde_Imap_Client::STATUS_UIDVALIDITY); - $md = $this->_cache->getMetaData($this->_selected, $uidvalid, array(self::CACHE_MODSEQ)); - - if (isset($md[self::CACHE_MODSEQ])) { - if ($md[self::CACHE_MODSEQ] < $modseq) { - $set = true; - $sync = $md[self::CACHE_MODSEQ]; - } else { - $set = false; - $sync = 0; - } - $mbox_ob->setStatus(Horde_Imap_Client::STATUS_SYNCMODSEQ, $md[self::CACHE_MODSEQ]); - } else { - $set = true; - $sync = 0; - } - - /* $modseq can be 0 - NOMODSEQ - so don't store in that case. */ - if ($set && $modseq) { - $this->_cache->setMetaData($this->_selected, $uidvalid, array( - self::CACHE_MODSEQ => $modseq - )); - } - - return $sync; - } - - /** - * Synchronizes the current mailbox cache with the server (using CONDSTORE - * or QRESYNC). - */ - protected function _condstoreSync() - { - $mbox_ob = $this->_mailboxOb(); - - /* Check that modseqs are available in mailbox. */ - if (!($highestmodseq = $mbox_ob->getStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ)) || - !($modseq = $this->_updateModSeq($highestmodseq))) { - $mbox_ob->sync = true; - } - - if ($mbox_ob->sync) { - return; - } - - $uids_ob = $this->getIdsOb($this->_cache->get( - $this->_selected, - array(), - array(), - $mbox_ob->getStatus(Horde_Imap_Client::STATUS_UIDVALIDITY) - )); - - if (!count($uids_ob)) { - $mbox_ob->sync = true; - return; - } - - /* Are we caching flags? */ - if (array_key_exists(Horde_Imap_Client::FETCH_FLAGS, $this->_cacheFields())) { - $fquery = new Horde_Imap_Client_Fetch_Query(); - $fquery->flags(); - - /* Update flags in cache. Cache will be updated in _fetch(). */ - $this->_fetch(new Horde_Imap_Client_Fetch_Results(), array( - array( - '_query' => $fquery, - 'changedsince' => $modseq, - 'ids' => $uids_ob - ) - )); - } - - /* Search for deleted messages, and remove from cache. */ - $vanished = $this->vanished($this->_selected, $modseq, array( - 'ids' => $uids_ob - )); - if (!empty($vanished->ids)) { - $this->_deleteMsgs($this->_selected, $this->getIdsOb($vanished->ids)); - } - - $mbox_ob->sync = true; - } - - /** - * Provide the list of available caching fields. - * - * @return array The list of available caching fields (fields are in the - * key). - */ - protected function _cacheFields() - { - $c = $this->getParam('cache'); - $out = $c['fields']; - - if (!$this->_capability()->isEnabled('CONDSTORE')) { - unset($out[Horde_Imap_Client::FETCH_FLAGS]); - } - - return $out; - } - - /** - * Return the current mailbox synchronization status. - * - * @param mixed $mailbox A mailbox. Either a Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * - * @return array An array with status data. (This data is not guaranteed - * to have any specific format). - */ - protected function _syncStatus($mailbox) - { - $status = $this->status( - $mailbox, - Horde_Imap_Client::STATUS_HIGHESTMODSEQ | - Horde_Imap_Client::STATUS_MESSAGES | - Horde_Imap_Client::STATUS_UIDNEXT_FORCE | - Horde_Imap_Client::STATUS_UIDVALIDITY - ); - - $fields = array('uidnext', 'uidvalidity'); - if (empty($status['highestmodseq'])) { - $fields[] = 'messages'; - } else { - $fields[] = 'highestmodseq'; - } - - $out = array(); - $sync_map = array_flip(Horde_Imap_Client_Data_Sync::$map); - - foreach ($fields as $val) { - $out[$sync_map[$val]] = $status[$val]; - } - - return array_filter($out); - } - - /** - * Get a message UID by the Message-ID. Returns the last message in a - * mailbox that matches. - * - * @param Horde_Imap_Client_Mailbox $mailbox The mailbox to search - * @param string $msgid Message-ID. - * - * @return string UID (null if not found). - */ - protected function _getUidByMessageId($mailbox, $msgid) - { - if (!$msgid) { - return null; - } - - $query = new Horde_Imap_Client_Search_Query(); - $query->headerText('Message-ID', $msgid); - $res = $this->search($mailbox, $query, array( - 'results' => array(Horde_Imap_Client::SEARCH_RESULTS_MAX) - )); - - return $res['max']; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Base/Alerts.php b/lib/horde/framework/Horde/Imap/Client/Base/Alerts.php deleted file mode 100644 index a481688848d..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Base/Alerts.php +++ /dev/null @@ -1,105 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.24.0 - */ -class Horde_Imap_Client_Base_Alerts -implements SplSubject -{ - /** - * Alert data. - * - * @var object - */ - protected $_alert; - - /** - * Observers. - * - * @var array - */ - protected $_observers = array(); - - /** - * Add an alert. - * - * @param string $alert The alert string. - * @param string $type The alert type. - */ - public function add($alert, $type = null) - { - $this->_alert = new stdClass; - $this->_alert->alert = $alert; - if (!is_null($type)) { - $this->_alert->type = $type; - } - - $this->notify(); - } - - /** - * Returns the last alert received. - * - * @return object Alert information. Object with these properties: - *
-     *   - alert: (string) Alert string.
-     *   - type: (string) [OPTIONAL] Alert type.
-     * 
- */ - public function getLast() - { - return $this->_alert; - } - - /* SplSubject methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function attach(SplObserver $observer) - { - $this->detach($observer); - $this->_observers[] = $observer; - } - - /** - */ - #[ReturnTypeWillChange] - public function detach(SplObserver $observer) - { - if (($key = array_search($observer, $this->_observers, true)) !== false) { - unset($this->_observers[$key]); - } - } - - /** - * Notification is triggered internally whenever the object's internal - * data storage is altered. - */ - #[ReturnTypeWillChange] - public function notify() - { - foreach ($this->_observers as $val) { - $val->update($this); - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Base/Debug.php b/lib/horde/framework/Horde/Imap/Client/Base/Debug.php deleted file mode 100644 index 2c922ad17f2..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Base/Debug.php +++ /dev/null @@ -1,152 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @internal - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Base_Debug -{ - /** Time, in seconds, to be labeled a slow command. */ - const SLOW_CMD = 5; - - /** - * Is debugging active? - * - * @var boolean - */ - public $debug = true; - - /** - * The debug stream. - * - * @var resource - */ - protected $_stream; - - /** - * Timestamp of last command. - * - * @var integer - */ - protected $_time = null; - - /** - * Constructor. - * - * @param mixed $debug The debug target. - */ - public function __construct($debug) - { - $this->_stream = is_resource($debug) - ? $debug - : @fopen($debug, 'a'); - register_shutdown_function(array($this, 'shutdown')); - } - - /** - * Shutdown function. - */ - public function shutdown() - { - if (is_resource($this->_stream)) { - fflush($this->_stream); - fclose($this->_stream); - $this->_stream = null; - } - } - - /** - * Write client output to debug log. - * - * @param string $msg Debug message. - */ - public function client($msg) - { - $this->_write($msg . "\n", 'C: '); - } - - /** - * Write informational message to debug log. - * - * @param string $msg Debug message. - */ - public function info($msg) - { - $this->_write($msg . "\n", '>> '); - } - - /** - * Write server output to debug log. - * - * @param string $msg Debug message. - */ - public function raw($msg) - { - $this->_write($msg); - } - - /** - * Write server output to debug log. - * - * @param string $msg Debug message. - */ - public function server($msg) - { - $this->_write($msg . "\n", 'S: '); - } - - /** - * Write debug information to the output stream. - * - * @param string $msg Debug data. - */ - protected function _write($msg, $pre = null) - { - if (!$this->debug || !$this->_stream) { - return; - } - - if (!is_null($pre)) { - $new_time = microtime(true); - - if (is_null($this->_time)) { - fwrite( - $this->_stream, - str_repeat('-', 30) . "\n" . '>> ' . date('r') . "\n" - ); - } elseif (($diff = ($new_time - $this->_time)) > self::SLOW_CMD) { - fwrite( - $this->_stream, - '>> Slow Command: ' . round($diff, 3) . " seconds\n" - ); - } - - $this->_time = $new_time; - } - - fwrite($this->_stream, $pre . $msg); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Base/Deprecated.php b/lib/horde/framework/Horde/Imap/Client/Base/Deprecated.php deleted file mode 100644 index dd9f708b4d3..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Base/Deprecated.php +++ /dev/null @@ -1,109 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @internal - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Base_Deprecated -{ - /** - * Returns a unique identifier for the current mailbox status. - * - * @param Horde_Imap_Client_Base $base_ob The base driver object. - * @param mixed $mailbox A mailbox. Either a - * Horde_Imap_Client_Mailbox - * object or a string (UTF-8). - * @param boolean $condstore Is CONDSTORE enabled? - * @param array $addl Additional cache info to add to - * the cache ID string. - * - * @return string The cache ID string, which will change when the - * composition of the mailbox changes. The uidvalidity - * will always be the first element, and will be delimited - * by the '|' character. - * - * @throws Horde_Imap_Client_Exception - */ - public static function getCacheId($base_ob, $mailbox, $condstore, - array $addl = array()) - { - $query = Horde_Imap_Client::STATUS_UIDVALIDITY | Horde_Imap_Client::STATUS_MESSAGES | Horde_Imap_Client::STATUS_UIDNEXT; - - /* Use MODSEQ as cache ID if CONDSTORE extension is available. */ - if ($condstore) { - $query |= Horde_Imap_Client::STATUS_HIGHESTMODSEQ; - } else { - $query |= Horde_Imap_Client::STATUS_UIDNEXT_FORCE; - } - - $status = $base_ob->status($mailbox, $query); - - if (empty($status['highestmodseq'])) { - $parts = array( - 'V' . $status['uidvalidity'], - 'U' . $status['uidnext'], - 'M' . $status['messages'] - ); - } else { - $parts = array( - 'V' . $status['uidvalidity'], - 'H' . $status['highestmodseq'] - ); - } - - return implode('|', array_merge($parts, $addl)); - } - - /** - * Parses a cacheID created by getCacheId(). - * - * @param string $id The cache ID. - * - * @return array An array with the following information: - * - highestmodseq: (integer) - * - messages: (integer) - * - uidnext: (integer) - * - uidvalidity: (integer) Always present - */ - public static function parseCacheId($id) - { - $data = array( - 'H' => 'highestmodseq', - 'M' => 'messages', - 'U' => 'uidnext', - 'V' => 'uidvalidity' - ); - $info = array(); - - foreach (explode('|', $id) as $part) { - if (isset($data[$part[0]])) { - $info[$data[$part[0]]] = intval(substr($part, 1)); - } - } - - return $info; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Base/Mailbox.php b/lib/horde/framework/Horde/Imap/Client/Base/Mailbox.php deleted file mode 100644 index 85151a62135..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Base/Mailbox.php +++ /dev/null @@ -1,187 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @internal - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Base_Mailbox -{ - /** - * Mapping object. - * - * @var Horde_Imap_Client_Ids_Map - */ - public $map; - - /** - * Is mailbox opened? - * - * @var boolean - */ - public $open; - - /** - * Is mailbox sync'd with remote server (via CONDSTORE/QRESYNC)? - * - * @var boolean - */ - public $sync; - - /** - * Status information. - * - * @var array - */ - protected $_status = array(); - - /** - * Constructor. - */ - public function __construct() - { - $this->reset(); - } - - /** - * Get status information for the mailbox. - * - * @param integer $entry STATUS_* constant. - * - * @return mixed Status information. - */ - public function getStatus($entry) - { - if (isset($this->_status[$entry])) { - return $this->_status[$entry]; - } - - switch ($entry) { - case Horde_Imap_Client::STATUS_FLAGS: - case Horde_Imap_Client::STATUS_SYNCFLAGUIDS: - case Horde_Imap_Client::STATUS_SYNCVANISHED: - return array(); - - case Horde_Imap_Client::STATUS_FIRSTUNSEEN: - /* If we know there are no messages in the current mailbox, we - * know there are no unseen messages. */ - return empty($this->_status[Horde_Imap_Client::STATUS_MESSAGES]) - ? false - : null; - - case Horde_Imap_Client::STATUS_RECENT_TOTAL: - case Horde_Imap_Client::STATUS_SYNCMODSEQ: - return 0; - - case Horde_Imap_Client::STATUS_PERMFLAGS: - /* If PERMFLAGS is not returned by server, must assume that all - * flags can be changed permanently (RFC 3501 [6.3.1]). */ - $flags = isset($this->_status[Horde_Imap_Client::STATUS_FLAGS]) - ? $this->_status[Horde_Imap_Client::STATUS_FLAGS] - : array(); - $flags[] = "\\*"; - return $flags; - - case Horde_Imap_Client::STATUS_UIDNOTSTICKY: - /* In the absence of explicit uidnotsticky identification, assume - * that UIDs are sticky. */ - return false; - - case Horde_Imap_Client::STATUS_UNSEEN: - /* If we know there are no messages in the current mailbox, we - * know there are no unseen messages . */ - return empty($this->_status[Horde_Imap_Client::STATUS_MESSAGES]) - ? 0 - : null; - - default: - return null; - } - } - - /** - * Set status information for the mailbox. - * - * @param integer $entry STATUS_* constant. - * @param mixed $value Status information. - */ - public function setStatus($entry, $value) - { - switch ($entry) { - case Horde_Imap_Client::STATUS_FIRSTUNSEEN: - case Horde_Imap_Client::STATUS_HIGHESTMODSEQ: - case Horde_Imap_Client::STATUS_MESSAGES: - case Horde_Imap_Client::STATUS_UNSEEN: - case Horde_Imap_Client::STATUS_UIDNEXT: - case Horde_Imap_Client::STATUS_UIDVALIDITY: - $value = intval($value); - break; - - case Horde_Imap_Client::STATUS_RECENT: - /* Keep track of RECENT_TOTAL information. */ - $this->_status[Horde_Imap_Client::STATUS_RECENT_TOTAL] = isset($this->_status[Horde_Imap_Client::STATUS_RECENT_TOTAL]) - ? ($this->_status[Horde_Imap_Client::STATUS_RECENT_TOTAL] + $value) - : intval($value); - break; - - case Horde_Imap_Client::STATUS_SYNCMODSEQ: - /* This is only set once per access. */ - if (isset($this->_status[$entry])) { - return; - } - $value = intval($value); - break; - - case Horde_Imap_Client::STATUS_SYNCFLAGUIDS: - case Horde_Imap_Client::STATUS_SYNCVANISHED: - if (!isset($this->_status[$entry])) { - $this->_status[$entry] = array(); - } - $this->_status[$entry] = array_merge($this->_status[$entry], $value); - return; - } - - $this->_status[$entry] = $value; - } - - /** - * Reset the mailbox information. - */ - public function reset() - { - $keep = array( - Horde_Imap_Client::STATUS_SYNCFLAGUIDS, - Horde_Imap_Client::STATUS_SYNCMODSEQ, - Horde_Imap_Client::STATUS_SYNCVANISHED - ); - - foreach (array_diff(array_keys($this->_status), $keep) as $val) { - unset($this->_status[$val]); - } - - $this->map = new Horde_Imap_Client_Ids_Map(); - $this->open = $this->sync = false; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Base/Password.php b/lib/horde/framework/Horde/Imap/Client/Base/Password.php deleted file mode 100644 index 06d3a224344..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Base/Password.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.14.0 - */ -interface Horde_Imap_Client_Base_Password -{ - /** - * Return the password to use for the server connection. - * - * @return string The password. - */ - public function getPassword(); - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Cache.php b/lib/horde/framework/Horde/Imap/Client/Cache.php deleted file mode 100644 index 47dc35c11ea..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Cache.php +++ /dev/null @@ -1,263 +0,0 @@ - - * @category Horde - * @copyright 2005-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Cache -{ - /** - * Base client object. - * - * @var Horde_Imap_Client_Base - */ - protected $_baseob; - - /** - * Storage backend. - * - * @var Horde_Imap_Client_Cache_Backend - */ - protected $_backend; - - /** - * Debug output. - * - * @var Horde_Imap_Client_Base_Debug - */ - protected $_debug = false; - - /** - * The configuration params. - * - * @var array - */ - protected $_params = array(); - - /** - * Constructor. - * - * @param array $params Configuration parameters: - *
-     *   - REQUIRED Parameters:
-     *     - backend: (Horde_Imap_Client_Cache_Backend) The cache backend.
-     *     - baseob: (Horde_Imap_Client_Base) The base client object.
-     *
-     *   - Optional Parameters:
-     *     - debug: (Horde_Imap_Client_Base_Debug) Debug object.
-     *              DEFAULT: No debug output
-     * 
- */ - public function __construct(array $params = array()) - { - $this->_backend = $params['backend']; - $this->_baseob = $params['baseob']; - - $this->_backend->setParams(array( - 'hostspec' => $this->_baseob->getParam('hostspec'), - 'port' => $this->_baseob->getParam('port'), - 'username' => $this->_baseob->getParam('username') - )); - - if (isset($params['debug']) && - ($params['debug'] instanceof Horde_Imap_Client_Base_Debug)) { - $this->_debug = $params['debug']; - $this->_debug->info(sprintf( - 'CACHE: Using the %s storage driver.', - get_class($this->_backend) - )); - } - } - - /** - * Get information from the cache. - * - * @param string $mailbox An IMAP mailbox string. - * @param array $uids The list of message UIDs to retrieve - * information for. If empty, returns the list - * of cached UIDs. - * @param array $fields An array of fields to retrieve. If empty, - * returns all cached fields. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - * - * @return array An array of arrays with the UID of the message as the - * key (if found) and the fields as values (will be - * undefined if not found). If $uids is empty, returns the - * full (unsorted) list of cached UIDs. - */ - public function get($mailbox, array $uids = array(), $fields = array(), - $uidvalid = null) - { - $mailbox = strval($mailbox); - - if (empty($uids)) { - $ret = $this->_backend->getCachedUids($mailbox, $uidvalid); - } else { - $ret = $this->_backend->get($mailbox, $uids, $fields, $uidvalid); - - if ($this->_debug && !empty($ret)) { - $this->_debug->info(sprintf( - 'CACHE: Retrieved messages (%s [%s; %s])', - empty($fields) ? 'ALL' : implode(',', $fields), - $mailbox, - $this->_baseob->getIdsOb(array_keys($ret))->tostring_sort - )); - } - } - - return $ret; - } - - /** - * Store information in cache. - * - * @param string $mailbox An IMAP mailbox string. - * @param array $data The list of data to save. The keys are the - * UIDs, the values are an array of information - * to save. If empty, do a check to make sure - * the uidvalidity is still valid. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - */ - public function set($mailbox, $data, $uidvalid) - { - $mailbox = strval($mailbox); - - if (empty($data)) { - $this->_backend->getMetaData($mailbox, $uidvalid, array('uidvalid')); - } else { - $this->_backend->set($mailbox, $data, $uidvalid); - - if ($this->_debug) { - $this->_debug->info(sprintf( - 'CACHE: Stored messages [%s; %s]', - $mailbox, - $this->_baseob->getIdsOb(array_keys($data))->tostring_sort - )); - } - } - } - - /** - * Get metadata information for a mailbox. - * - * @param string $mailbox An IMAP mailbox string. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - * @param array $entries An array of entries to return. If empty, - * returns all metadata. - * - * @return array The requested metadata. Requested entries that do not - * exist will be undefined. The following entries are - * defaults and always present: - * - uidvalid: (integer) The UIDVALIDITY of the mailbox. - */ - public function getMetaData($mailbox, $uidvalid = null, - array $entries = array()) - { - return $this->_backend->getMetaData(strval($mailbox), $uidvalid, $entries); - } - - /** - * Set metadata information for a mailbox. - * - * @param string $mailbox An IMAP mailbox string. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - * @param array $data The list of data to save. The keys are the - * metadata IDs, the values are the associated - * data. The following labels are reserved: - * 'uidvalid'. - */ - public function setMetaData($mailbox, $uidvalid, array $data = array()) - { - unset($data['uidvalid']); - - if (!empty($data)) { - if (!empty($uidvalid)) { - $data['uidvalid'] = $uidvalid; - } - $mailbox = strval($mailbox); - - $this->_backend->setMetaData($mailbox, $data); - - if ($this->_debug) { - $this->_debug->info(sprintf( - 'CACHE: Stored metadata (%s [%s])', - implode(',', array_keys($data)), - $mailbox - )); - } - } - } - - /** - * Delete messages in the cache. - * - * @param string $mailbox An IMAP mailbox string. - * @param array $uids The list of message UIDs to delete. - */ - public function deleteMsgs($mailbox, $uids) - { - if (empty($uids)) { - return; - } - - $mailbox = strval($mailbox); - - $this->_backend->deleteMsgs($mailbox, $uids); - - if ($this->_debug) { - $this->_debug->info(sprintf( - 'CACHE: Deleted messages [%s; %s]', - $mailbox, - $this->_baseob->getIdsOb($uids)->tostring_sort - )); - } - } - - /** - * Delete a mailbox from the cache. - * - * @param string $mbox The mailbox to delete. - */ - public function deleteMailbox($mbox) - { - $mbox = strval($mbox); - $this->_backend->deleteMailbox($mbox); - - if ($this->_debug) { - $this->_debug->info(sprintf( - 'CACHE: Deleted mailbox [%s]', - $mbox - )); - } - } - - /** - * Clear the cache. - * - * @since 2.9.0 - * - * @param integer $lifetime Only delete entries older than this (in - * seconds). If null, deletes all entries. - */ - public function clear($lifetime = null) - { - $this->_backend->clear($lifetime); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Cache/Backend.php b/lib/horde/framework/Horde/Imap/Client/Cache/Backend.php deleted file mode 100644 index 610b26ad0ec..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Cache/Backend.php +++ /dev/null @@ -1,177 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -abstract class Horde_Imap_Client_Cache_Backend implements Serializable -{ - /** - * Configuration paramters. - * Values set by the base Cache object: hostspec, port, username - * - * @var array - */ - protected $_params = array(); - - /** - * Constructor. - * - * @param array $params Configuration parameters. - */ - public function __construct(array $params = array()) - { - $this->setParams($params); - $this->_initOb(); - } - - /** - * Initialization tasks. - */ - protected function _initOb() - { - } - - /** - * Add configuration parameters. - * - * @param array $params Configuration parameters. - */ - public function setParams(array $params = array()) - { - $this->_params = array_merge($this->_params, $params); - } - - /** - * Get information from the cache for a set of UIDs. - * - * @param string $mailbox An IMAP mailbox string. - * @param array $uids The list of message UIDs to retrieve - * information for. - * @param array $fields An array of fields to retrieve. If empty, - * returns all cached fields. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - * - * @return array An array of arrays with the UID of the message as the - * key (if found) and the fields as values (will be - * undefined if not found). - */ - abstract public function get($mailbox, $uids, $fields, $uidvalid); - - /** - * Get the list of cached UIDs. - * - * @param string $mailbox An IMAP mailbox string. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - * - * @return array The (unsorted) list of cached UIDs. - */ - abstract public function getCachedUids($mailbox, $uidvalid); - - /** - * Store data in cache. - * - * @param string $mailbox An IMAP mailbox string. - * @param array $data The list of data to save. The keys are the - * UIDs, the values are an array of information - * to save. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - */ - abstract public function set($mailbox, $data, $uidvalid); - - /** - * Get metadata information for a mailbox. - * - * @param string $mailbox An IMAP mailbox string. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - * @param array $entries An array of entries to return. If empty, - * returns all metadata. - * - * @return array The requested metadata. Requested entries that do not - * exist will be undefined. The following entries are - * defaults and always present: - * - uidvalid: (integer) The UIDVALIDITY of the mailbox. - */ - abstract public function getMetaData($mailbox, $uidvalid, $entries); - - /** - * Set metadata information for a mailbox. - * - * @param string $mailbox An IMAP mailbox string. - * @param array $data The list of data to save. The keys are the - * metadata IDs, the values are the associated - * data. (If present, uidvalidity appears as - * the 'uidvalid' key in $data.) - */ - abstract public function setMetaData($mailbox, $data); - - /** - * Delete messages in the cache. - * - * @param string $mailbox An IMAP mailbox string. - * @param array $uids The list of message UIDs to delete. - */ - abstract public function deleteMsgs($mailbox, $uids); - - /** - * Delete a mailbox from the cache. - * - * @param string $mailbox The mailbox to delete. - */ - abstract public function deleteMailbox($mailbox); - - /** - * Clear the cache. - * - * @param integer $lifetime Only delete entries older than this (in - * seconds). If null, deletes all entries. - */ - abstract public function clear($lifetime); - - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $this->__unserialize(unserialize($data)); - } - - /** - * @return array - */ - public function __serialize() - { - return $this->_params; - } - - public function __unserialize(array $data) - { - $this->_params = $data; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Cache.php b/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Cache.php deleted file mode 100644 index d8fa4fd116a..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Cache.php +++ /dev/null @@ -1,514 +0,0 @@ - - * @category Horde - * @copyright 2005-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Cache_Backend_Cache -extends Horde_Imap_Client_Cache_Backend -{ - /** Cache structure version. */ - const VERSION = 3; - - /** - * The cache object. - * - * @var Horde_Cache - */ - protected $_cache; - - /** - * The working data for the current pageload. All changes take place to - * this data. - * - * @var array - */ - protected $_data = array(); - - /** - * The list of cache slices loaded. - * - * @var array - */ - protected $_loaded = array(); - - /** - * The mapping of UIDs to slices. - * - * @var array - */ - protected $_slicemap = array(); - - /** - * The list of items to update: - * - add: (array) List of IDs that were added. - * - slice: (array) List of slices that were modified. - * - slicemap: (boolean) Was slicemap info changed? - * - * @var array - */ - protected $_update = array(); - - /** - * Constructor. - * - * @param array $params Configuration parameters: - *
-     *   - REQUIRED Parameters:
-     *     - cacheob: (Horde_Cache) The cache object to use.
-     *
-     *   - Optional Parameters:
-     *     - lifetime: (integer) The lifetime of the cache data (in seconds).
-     *                 DEFAULT: 1 week (604800 seconds)
-     *     - slicesize: (integer) The slicesize to use.
-     *                  DEFAULT: 50
-     * 
- */ - public function __construct(array $params = array()) - { - // Default parameters. - $params = array_merge(array( - 'lifetime' => 604800, - 'slicesize' => 50 - ), array_filter($params)); - - if (!isset($params['cacheob'])) { - throw new InvalidArgumentException('Missing cacheob parameter.'); - } - - foreach (array('lifetime', 'slicesize') as $val) { - $params[$val] = intval($params[$val]); - } - - parent::__construct($params); - } - - /** - * Initialization tasks. - */ - protected function _initOb() - { - $this->_cache = $this->_params['cacheob']; - register_shutdown_function(array($this, 'save')); - } - - /** - * Updates the cache. - */ - public function save() - { - $lifetime = $this->_params['lifetime']; - - foreach ($this->_update as $mbox => $val) { - $s = &$this->_slicemap[$mbox]; - - try { - if (!empty($val['add'])) { - if ($s['c'] <= $this->_params['slicesize']) { - $val['slice'][] = $s['i']; - $this->_loadSlice($mbox, $s['i']); - } - $val['slicemap'] = true; - - foreach (array_keys(array_flip($val['add'])) as $uid) { - if ($s['c']++ > $this->_params['slicesize']) { - $s['c'] = 0; - $val['slice'][] = ++$s['i']; - $this->_loadSlice($mbox, $s['i']); - } - $s['s'][$uid] = $s['i']; - } - } - - if (!empty($val['slice'])) { - $d = &$this->_data[$mbox]; - $val['slicemap'] = true; - - foreach (array_keys(array_flip($val['slice'])) as $slice) { - $data = array(); - foreach (moodle_array_keys_filter($s['s'], $slice) as $uid) { - $data[$uid] = is_array($d[$uid]) - ? serialize($d[$uid]) - : $d[$uid]; - } - $this->_cache->set($this->_getCid($mbox, $slice), serialize($data), $lifetime); - } - } - - if (!empty($val['slicemap'])) { - $this->_cache->set($this->_getCid($mbox, 'slicemap'), serialize($s), $lifetime); - } - } catch (Horde_Exception $e) { - } - } - - $this->_update = array(); - } - - /** - */ - public function get($mailbox, $uids, $fields, $uidvalid) - { - $ret = array(); - $this->_loadUids($mailbox, $uids, $uidvalid); - - if (empty($this->_data[$mailbox])) { - return $ret; - } - - if (!empty($fields)) { - $fields = array_flip($fields); - } - $ptr = &$this->_data[$mailbox]; - - foreach (array_intersect($uids, array_keys($ptr)) as $val) { - if (is_string($ptr[$val])) { - try { - $ptr[$val] = @unserialize($ptr[$val]); - } catch (Exception $e) {} - } - - $ret[$val] = (empty($fields) || empty($ptr[$val])) - ? $ptr[$val] - : array_intersect_key($ptr[$val], $fields); - } - - return $ret; - } - - /** - */ - public function getCachedUids($mailbox, $uidvalid) - { - $this->_loadSliceMap($mailbox, $uidvalid); - return array_unique(array_merge( - array_keys($this->_slicemap[$mailbox]['s']), - (isset($this->_update[$mailbox]) ? $this->_update[$mailbox]['add'] : array()) - )); - } - - /** - */ - public function set($mailbox, $data, $uidvalid) - { - $update = array_keys($data); - - try { - $this->_loadUids($mailbox, $update, $uidvalid); - } catch (Horde_Imap_Client_Exception $e) { - // Ignore invalidity - just start building the new cache - } - - $d = &$this->_data[$mailbox]; - $s = &$this->_slicemap[$mailbox]['s']; - $add = $updated = array(); - - foreach ($data as $k => $v) { - if (isset($d[$k])) { - if (is_string($d[$k])) { - try { - $d[$k] = @unserialize($d[$k]); - } catch (Exception $e) {} - } - $d[$k] = is_array($d[$k]) - ? array_merge($d[$k], $v) - : $v; - if (isset($s[$k])) { - $updated[$s[$k]] = true; - } - } else { - $d[$k] = $v; - $add[] = $k; - } - } - - $this->_toUpdate($mailbox, 'add', $add); - $this->_toUpdate($mailbox, 'slice', array_keys($updated)); - } - - /** - */ - public function getMetaData($mailbox, $uidvalid, $entries) - { - $this->_loadSliceMap($mailbox, $uidvalid); - - return empty($entries) - ? $this->_slicemap[$mailbox]['d'] - : array_intersect_key($this->_slicemap[$mailbox]['d'], array_flip($entries)); - } - - /** - */ - public function setMetaData($mailbox, $data) - { - $this->_loadSliceMap($mailbox, isset($data['uidvalid']) ? $data['uidvalid'] : null); - $this->_slicemap[$mailbox]['d'] = array_merge($this->_slicemap[$mailbox]['d'], $data); - $this->_toUpdate($mailbox, 'slicemap', true); - } - - /** - */ - public function deleteMsgs($mailbox, $uids) - { - if (empty($uids)) { - return; - } - - $this->_loadSliceMap($mailbox); - - $slicemap = &$this->_slicemap[$mailbox]; - $deleted = array_intersect_key($slicemap['s'], array_flip($uids)); - - if (isset($this->_update[$mailbox])) { - $this->_update[$mailbox]['add'] = array_diff( - $this->_update[$mailbox]['add'], - $uids - ); - } - - if (empty($deleted)) { - return; - } - - $this->_loadUids($mailbox, array_keys($deleted)); - $d = &$this->_data[$mailbox]; - - foreach (array_keys($deleted) as $id) { - unset($d[$id], $slicemap['s'][$id]); - } - - foreach (array_unique($deleted) as $slice) { - /* Get rid of slice if less than 10% of capacity. */ - if (($slice != $slicemap['i']) && - ($slice_uids = moodle_array_keys_filter($slicemap['s'], $slice)) && - ($this->_params['slicesize'] * 0.1) > count($slice_uids)) { - $this->_toUpdate($mailbox, 'add', $slice_uids); - $this->_cache->expire($this->_getCid($mailbox, $slice)); - foreach ($slice_uids as $val) { - unset($slicemap['s'][$val]); - } - } else { - $this->_toUpdate($mailbox, 'slice', array($slice)); - } - } - } - - /** - */ - public function deleteMailbox($mailbox) - { - $this->_loadSliceMap($mailbox); - $this->_deleteMailbox($mailbox); - } - - /** - */ - public function clear($lifetime) - { - $this->_cache->clear(); - $this->_data = $this->_loaded = $this->_slicemap = $this->_update = array(); - } - - /** - * Create the unique ID used to store the data in the cache. - * - * @param string $mailbox The mailbox to cache. - * @param string $slice The cache slice. - * - * @return string The cache ID. - */ - protected function _getCid($mailbox, $slice) - { - return implode('|', array( - 'horde_imap_client', - $this->_params['username'], - $mailbox, - $this->_params['hostspec'], - $this->_params['port'], - $slice, - self::VERSION - )); - } - - /** - * Delete a mailbox from the cache. - * - * @param string $mbox The mailbox to delete. - */ - protected function _deleteMailbox($mbox) - { - foreach (array_merge(array_keys(array_flip($this->_slicemap[$mbox]['s'])), array('slicemap')) as $slice) { - $cid = $this->_getCid($mbox, $slice); - $this->_cache->expire($cid); - unset($this->_loaded[$cid]); - } - - unset( - $this->_data[$mbox], - $this->_slicemap[$mbox], - $this->_update[$mbox] - ); - } - - /** - * Load UIDs by regenerating from the cache. - * - * @param string $mailbox The mailbox to load. - * @param array $uids The UIDs to load. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - */ - protected function _loadUids($mailbox, $uids, $uidvalid = null) - { - if (!isset($this->_data[$mailbox])) { - $this->_data[$mailbox] = array(); - } - - $this->_loadSliceMap($mailbox, $uidvalid); - - if (!empty($uids)) { - foreach (array_unique(array_intersect_key($this->_slicemap[$mailbox]['s'], array_flip($uids))) as $slice) { - $this->_loadSlice($mailbox, $slice); - } - } - } - - /** - * Load UIDs from a cache slice. - * - * @param string $mailbox The mailbox to load. - * @param integer $slice The slice to load. - */ - protected function _loadSlice($mailbox, $slice) - { - $cache_id = $this->_getCid($mailbox, $slice); - - if (!empty($this->_loaded[$cache_id])) { - return; - } - - if (($data = $this->_cache->get($cache_id, 0)) !== false) { - try { - $data = @unserialize($data); - } catch (Exception $e) {} - } - - if (($data !== false) && is_array($data)) { - $this->_data[$mailbox] += $data; - $this->_loaded[$cache_id] = true; - } else { - $ptr = &$this->_slicemap[$mailbox]; - - // Slice data is corrupt; remove from slicemap. - foreach (moodle_array_keys_filter($ptr['s'], $slice) as $val) { - unset($ptr['s'][$val]); - } - - if ($slice == $ptr['i']) { - $ptr['c'] = 0; - } - } - } - - /** - * Load the slicemap for a given mailbox. The slicemap contains - * the uidvalidity information, the UIDs->slice lookup table, and any - * metadata that needs to be saved for the mailbox. - * - * @param string $mailbox The mailbox. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - */ - protected function _loadSliceMap($mailbox, $uidvalid = null) - { - if (!isset($this->_slicemap[$mailbox]) && - (($data = $this->_cache->get($this->_getCid($mailbox, 'slicemap'), 0)) !== false)) { - try { - if (($slice = @unserialize($data)) && - is_array($slice)) { - $this->_slicemap[$mailbox] = $slice; - } - } catch (Exception $e) {} - } - - if (isset($this->_slicemap[$mailbox])) { - $ptr = &$this->_slicemap[$mailbox]; - if (is_null($ptr['d']['uidvalid'])) { - $ptr['d']['uidvalid'] = $uidvalid; - return; - } elseif (!is_null($uidvalid) && - ($ptr['d']['uidvalid'] != $uidvalid)) { - $this->_deleteMailbox($mailbox); - } else { - return; - } - } - - $this->_slicemap[$mailbox] = array( - // Tracking count for purposes of determining slices - 'c' => 0, - // Metadata storage - // By default includes UIDVALIDITY of mailbox. - 'd' => array('uidvalid' => $uidvalid), - // The ID of the last slice. - 'i' => 0, - // The slice list. - 's' => array() - ); - } - - /** - * Add update entry for a mailbox. - * - * @param string $mailbox The mailbox. - * @param string $type 'add', 'slice', or 'slicemap'. - * @param mixed $data The data to update. - */ - protected function _toUpdate($mailbox, $type, $data) - { - if (!isset($this->_update[$mailbox])) { - $this->_update[$mailbox] = array( - 'add' => array(), - 'slice' => array() - ); - } - - $this->_update[$mailbox][$type] = ($type == 'slicemap') - ? $data - : array_merge($this->_update[$mailbox][$type], $data); - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return $this->__serialize(); - } - - /** - * @return array - */ - public function __serialize() - { - $this->save(); - return parent::__serialize(); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Db.php b/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Db.php deleted file mode 100644 index 6bcb43cbea6..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Db.php +++ /dev/null @@ -1,407 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Cache_Backend_Db -extends Horde_Imap_Client_Cache_Backend -{ - /** SQL table names. */ - const BASE_TABLE = 'horde_imap_client_data'; - const MD_TABLE = 'horde_imap_client_metadata'; - const MSG_TABLE = 'horde_imap_client_message'; - - /** - * Handle for the database connection. - * - * @var Horde_Db_Adapter - */ - protected $_db; - - /** - * Constructor. - * - * @param array $params Configuration parameters: - *
-     *   - REQUIRED Parameters:
-     *     - db: (Horde_Db_Adapter) DB object.
-     * 
- */ - public function __construct(array $params = array()) - { - if (!isset($params['db'])) { - throw new InvalidArgumentException('Missing db parameter.'); - } - - parent::__construct($params); - } - - /** - */ - protected function _initOb() - { - $this->_db = $this->_params['db']; - } - - /** - */ - public function get($mailbox, $uids, $fields, $uidvalid) - { - $this->getMetaData($mailbox, $uidvalid, array('uidvalid')); - - $query = $this->_baseSql($mailbox, self::MSG_TABLE); - $query[0] = 'SELECT t.data, t.msguid ' . $query[0]; - - $uid_query = array(); - foreach ($uids as $val) { - $uid_query[] = 't.msguid = ?'; - $query[1][] = strval($val); - } - $query[0] .= ' AND (' . implode(' OR ', $uid_query) . ')'; - - $compress = new Horde_Compress_Fast(); - $out = array(); - - try { - $columns = $this->_db->columns(self::MSG_TABLE); - $res = $this->_db->select($query[0], $query[1]); - - foreach ($res as $row) { - try { - $out[$row['msguid']] = @unserialize($compress->decompress( - $columns['data']->binaryToString($row['data']) - )); - } catch (Exception $e) {} - } - } catch (Horde_Db_Exception $e) {} - - return $out; - } - - /** - */ - public function getCachedUids($mailbox, $uidvalid) - { - $this->getMetaData($mailbox, $uidvalid, array('uidvalid')); - - $query = $this->_baseSql($mailbox, self::MSG_TABLE); - $query[0] = 'SELECT DISTINCT t.msguid ' . $query[0]; - - try { - return $this->_db->selectValues($query[0], $query[1]); - } catch (Horde_Db_Exception $e) { - return array(); - } - } - - /** - */ - public function set($mailbox, $data, $uidvalid) - { - if ($uid = $this->_getUid($mailbox)) { - $res = $this->get($mailbox, array_keys($data), array(), $uidvalid); - } else { - $res = array(); - $uid = $this->_createUid($mailbox); - } - - $compress = new Horde_Compress_Fast(); - - foreach ($data as $key => $val) { - if (isset($res[$key])) { - try { - /* Update */ - $this->_db->updateBlob( - self::MSG_TABLE, - array('data' => new Horde_Db_Value_Binary($compress->compress(serialize(array_merge($res[$key], $val))))), - array( - 'messageid = ? AND msguid = ?', - array($uid, strval($key)) - ) - ); - } catch (Horde_Db_Exception $e) {} - } else { - /* Insert */ - try { - $this->_db->insertBlob( - self::MSG_TABLE, - array( - 'data' => new Horde_Db_Value_Binary($compress->compress(serialize($val))), - 'msguid' => strval($key), - 'messageid' => $uid - ) - ); - } catch (Horde_Db_Exception $e) {} - } - } - - /* Update modified time. */ - try { - $this->_db->update( - sprintf( - 'UPDATE %s SET modified = ? WHERE messageid = ?', - self::BASE_TABLE - ), - array(time(), $uid) - ); - } catch (Horde_Db_Exception $e) {} - - /* Update uidvalidity. */ - $this->setMetaData($mailbox, array('uidvalid' => $uidvalid)); - } - - /** - */ - public function getMetaData($mailbox, $uidvalid, $entries) - { - $query = $this->_baseSql($mailbox, self::MD_TABLE); - $query[0] = 'SELECT t.field, t.data ' . $query[0]; - - if (!empty($entries)) { - $entries[] = 'uidvalid'; - $entry_query = array(); - - foreach (array_unique($entries) as $val) { - $entry_query[] = 't.field = ?'; - $query[1][] = $val; - } - $query[0] .= ' AND (' . implode(' OR ', $entry_query) . ')'; - } - - try { - if ($res = $this->_db->selectAssoc($query[0], $query[1])) { - $columns = $this->_db->columns(self::MD_TABLE); - foreach ($res as $key => $val) { - switch ($key) { - case 'uidvalid': - $res[$key] = $columns['data']->binaryToString($val); - break; - - default: - try { - $res[$key] = @unserialize( - $columns['data']->binaryToString($val) - ); - } catch (Exception $e) {} - break; - } - } - - if (is_null($uidvalid) || - !isset($res['uidvalid']) || - ($res['uidvalid'] == $uidvalid)) { - return $res; - } - - $this->deleteMailbox($mailbox); - } - } catch (Horde_Db_Exception $e) {} - - return array(); - } - - /** - */ - public function setMetaData($mailbox, $data) - { - if (!($uid = $this->_getUid($mailbox))) { - $uid = $this->_createUid($mailbox); - } - - $query = sprintf('SELECT field FROM %s where messageid = ?', self::MD_TABLE); - $values = array($uid); - - try { - $fields = $this->_db->selectValues($query, $values); - } catch (Horde_Db_Exception $e) { - return; - } - - foreach ($data as $key => $val) { - $val = new Horde_Db_Value_Binary(($key == 'uidvalid') ? $val : serialize($val)); - - if (in_array($key, $fields)) { - /* Update */ - try { - $this->_db->updateBlob( - self::MD_TABLE, - array('data' => $val), - array('field = ? AND messageid = ?', array($key, $uid)) - ); - } catch (Horde_Db_Exception $e) {} - } else { - /* Insert */ - try { - $this->_db->insertBlob( - self::MD_TABLE, - array('data' => $val, 'field' => $key, 'messageid' => $uid) - ); - } catch (Horde_Db_Exception $e) {} - } - } - } - - /** - */ - public function deleteMsgs($mailbox, $uids) - { - if (empty($uids)) { - return; - } - - $query = $this->_baseSql($mailbox); - $query[0] = sprintf( - 'DELETE FROM %s WHERE messageid IN (SELECT messageid ' . $query[0] . ')', - self::MSG_TABLE - ); - - $uid_query = array(); - foreach ($uids as $val) { - $uid_query[] = 'msguid = ?'; - $query[1][] = strval($val); - } - $query[0] .= ' AND (' . implode(' OR ', $uid_query) . ')'; - - try { - $this->_db->delete($query[0], $query[1]); - } catch (Horde_Db_Exception $e) {} - } - - /** - */ - public function deleteMailbox($mailbox) - { - if (is_null($uid = $this->_getUid($mailbox))) { - return; - } - - foreach (array(self::BASE_TABLE, self::MD_TABLE, self::MSG_TABLE) as $val) { - try { - $this->_db->delete( - sprintf('DELETE FROM %s WHERE messageid = ?', $val), - array($uid) - ); - } catch (Horde_Db_Exception $e) {} - } - } - - /** - */ - public function clear($lifetime) - { - if (is_null($lifetime)) { - try { - $this->_db->delete(sprintf('DELETE FROM %s', self::BASE_TABLE)); - $this->_db->delete(sprintf('DELETE FROM %s', self::MD_TABLE)); - $this->_db->delete(sprintf('DELETE FROM %s', self::MSG_TABLE)); - } catch (Horde_Db_Exception $e) {} - return; - } - - $purge = time() - $lifetime; - $sql = 'DELETE FROM %s WHERE messageid IN (SELECT messageid FROM %s WHERE modified < ?)'; - - foreach (array(self::MD_TABLE, self::MSG_TABLE) as $val) { - try { - $this->_db->delete( - sprintf($sql, $val, self::BASE_TABLE), - array($purge) - ); - } catch (Horde_Db_Exception $e) { - } - } - - try { - $this->_db->delete( - sprintf('DELETE FROM %s WHERE modified < ?', self::BASE_TABLE), - array($purge) - ); - } catch (Horde_Db_Exception $e) { - } - } - - /** - * Prepare the base SQL query. - * - * @param string $mailbox The mailbox. - * @param string $join The table to join with the base table. - * - * @return array SQL query and bound parameters. - */ - protected function _baseSql($mailbox, $join = null) - { - $sql = sprintf('FROM %s d', self::BASE_TABLE); - - if (!is_null($join)) { - $sql .= sprintf(' INNER JOIN %s t ON d.messageid = t.messageid', $join); - } - - return array( - $sql . ' WHERE d.hostspec = ? AND d.port = ? AND d.username = ? AND d.mailbox = ?', - array( - $this->_params['hostspec'], - $this->_params['port'], - $this->_params['username'], - $mailbox - ) - ); - } - - /** - * @param string $mailbox - * - * @return string UID from base table. - */ - protected function _getUid($mailbox) - { - $query = $this->_baseSql($mailbox); - $query[0] = 'SELECT d.messageid ' . $query[0]; - - try { - return $this->_db->selectValue($query[0], $query[1]); - } catch (Horde_Db_Exception $e) { - return null; - } - } - - /** - * @param string $mailbox - * - * @return string UID from base table. - */ - protected function _createUid($mailbox) - { - return $this->_db->insert( - sprintf( - 'INSERT INTO %s (hostspec, mailbox, port, username) ' . - 'VALUES (?, ?, ?, ?)', - self::BASE_TABLE - ), - array( - $this->_params['hostspec'], - $mailbox, - $this->_params['port'], - $this->_params['username'] - ) - ); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Hashtable.php b/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Hashtable.php deleted file mode 100644 index bcbb40e45a8..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Hashtable.php +++ /dev/null @@ -1,421 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.17.0 - */ -class Horde_Imap_Client_Cache_Backend_Hashtable -extends Horde_Imap_Client_Cache_Backend -{ - /** Separator for CID between mailbox and UID. */ - const CID_SEPARATOR = '|'; - - /** - * The working data for the current pageload. All changes take place to - * this data. - * - * @var array - */ - protected $_data = array(); - - /** - * HashTable object. - * - * @var Horde_HashTable - */ - protected $_hash; - - /** - * Mailbox level data. - * - * @var array - */ - protected $_mbox = array(); - - /** - * Horde_Pack singleton object. - * - * @var Horde_Pack - */ - protected $_pack; - - /** - * List of mailbox/UIDs to update. - * Keys are mailboxes. Values are arrays with three possible keys: - *
-     *   - d: UIDs to delete
-     *   - m: Was metadata updated?
-     *   - u: UIDs to update
-     * 
- * - * @var array - */ - protected $_update = array(); - - /** - * Constructor. - * - * @param array $params Configuration parameters: - *
-     *   - REQUIRED parameters:
-     *     - hashtable: (Horde_HashTable) A HashTable object.
-     *
-     *   - Optional Parameters:
-     *     - lifetime: (integer) The lifetime of the cache data (in seconds).
-     *                 DEFAULT: 604800 seconds (1 week) [@since 2.19.0]
-     * 
- */ - public function __construct(array $params = array()) - { - if (!isset($params['hashtable'])) { - throw new InvalidArgumentException('Missing hashtable parameter.'); - } - - parent::__construct(array_merge(array( - 'lifetime' => 604800 - ), $params)); - } - - /** - */ - protected function _initOb() - { - $this->_hash = $this->_params['hashtable']; - $this->_pack = new Horde_Pack(); - register_shutdown_function(array($this, 'save')); - } - - /** - */ - public function get($mailbox, $uids, $fields, $uidvalid) - { - $ret = array(); - - if (empty($uids)) { - return $ret; - } - - $this->_loadUids($mailbox, $uids, $uidvalid); - - if (empty($this->_data[$mailbox])) { - return $ret; - } - - if (!empty($fields)) { - $fields = array_flip($fields); - } - $ptr = &$this->_data[$mailbox]; - $to_delete = array(); - - foreach ($uids as $val) { - if (isset($ptr[$val])) { - if (is_string($ptr[$val])) { - try { - $ptr[$val] = $this->_pack->unpack($ptr[$val]); - } catch (Horde_Pack_Exception $e) { - $to_delete[] = $val; - continue; - } - } - - $ret[$val] = (empty($fields) || empty($ptr[$val])) - ? $ptr[$val] - : array_intersect_key($ptr[$val], $fields); - } else { - $to_delete[] = $val; - } - } - - $this->deleteMsgs($mailbox, $to_delete); - - return $ret; - } - - /** - */ - public function getCachedUids($mailbox, $uidvalid) - { - $this->_loadMailbox($mailbox, $uidvalid); - return $this->_mbox[$mailbox]['u']->ids; - } - - /** - */ - public function set($mailbox, $data, $uidvalid) - { - $this->_loadUids($mailbox, array_keys($data), $uidvalid); - - $d = &$this->_data[$mailbox]; - $to_add = array(); - - foreach ($data as $k => $v) { - if (isset($d[$k]) && is_string($d[$k])) { - try { - $d[$k] = $this->_pack->unpack($d[$k]); - } catch (Horde_Pack_Exception $e) { - continue; - } - } - - $d[$k] = (isset($d[$k]) && is_array($d[$k])) - ? array_merge($d[$k], $v) - : $v; - $this->_update[$mailbox]['u'][$k] = true; - unset($this->_update[$mailbox]['d'][$k]); - $to_add[] = $k; - } - - if (!empty($to_add)) { - $this->_mbox[$mailbox]['u']->add($to_add); - $this->_update[$mailbox]['m'] = true; - } - } - - /** - */ - public function getMetaData($mailbox, $uidvalid, $entries) - { - $this->_loadMailbox($mailbox, $uidvalid); - - return empty($entries) - ? $this->_mbox[$mailbox]['d'] - : array_intersect_key($this->_mbox[$mailbox]['d'], array_flip($entries)); - } - - /** - */ - public function setMetaData($mailbox, $data) - { - $this->_loadMailbox($mailbox, isset($data['uidvalid']) ? $data['uidvalid'] : null); - - $this->_mbox[$mailbox]['d'] = array_merge( - $this->_mbox[$mailbox]['d'], - $data - ); - $this->_update[$mailbox]['m'] = true; - } - - /** - */ - public function deleteMsgs($mailbox, $uids) - { - if (empty($uids)) { - return; - } - - $this->_loadMailbox($mailbox); - - foreach ($uids as $val) { - unset( - $this->_data[$mailbox][$val], - $this->_update[$mailbox]['u'][$val] - ); - $this->_update[$mailbox]['d'][$val] = true; - } - - $this->_mbox[$mailbox]['u']->remove($uids); - $this->_update[$mailbox]['m'] = true; - } - - /** - */ - public function deleteMailbox($mailbox) - { - /* Do this action immediately, instead of at shutdown. Makes coding - * simpler. */ - $this->_loadMailbox($mailbox); - - $this->_hash->delete(array_merge( - array($this->_getCid($mailbox)), - array_values($this->_getMsgCids($mailbox, $this->_mbox[$mailbox]['u'])) - )); - - unset( - $this->_data[$mailbox], - $this->_mbox[$mailbox], - $this->_update[$mailbox] - ); - } - - /** - */ - public function clear($lifetime) - { - /* Only can clear mailboxes we know about. */ - foreach (array_keys($this->_mbox) as $val) { - $this->deleteMailbox($val); - } - - $this->_data = $this->_mbox = $this->_update = array(); - } - - /** - * Updates the cache. - */ - public function save() - { - foreach ($this->_update as $mbox => $val) { - try { - if (!empty($val['u'])) { - $ptr = &$this->_data[$mbox]; - foreach ($this->_getMsgCids($mbox, array_keys($val['u'])) as $k2 => $v2) { - try { - $this->_hash->set( - $v2, - $this->_pack->pack($ptr[$k2]), - array('expire' => $this->_params['lifetime']) - ); - } catch (Horde_Pack_Exception $e) { - $this->deleteMsgs($mbox, array($v2)); - $val['d'][] = $v2; - } - } - } - - if (!empty($val['d'])) { - $this->_hash->delete(array_values( - $this->_getMsgCids($mbox, $val['d']) - )); - } - - if (!empty($val['m'])) { - try { - $this->_hash->set( - $this->_getCid($mbox), - $this->_pack->pack($this->_mbox[$mbox]), - array('expire' => $this->_params['lifetime']) - ); - } catch (Horde_Pack_Exception $e) {} - } - } catch (Horde_Exception $e) { - } - } - - $this->_update = array(); - } - - /** - * Loads basic mailbox information. - * - * @param string $mailbox The mailbox to load. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - */ - protected function _loadMailbox($mailbox, $uidvalid = null) - { - if (!isset($this->_mbox[$mailbox]) && - ($ob = $this->_hash->get($this->_getCid($mailbox)))) { - try { - $this->_mbox[$mailbox] = $this->_pack->unpack($ob); - } catch (Horde_Pack_Exception $e) {} - } - - if (isset($this->_mbox[$mailbox])) { - if (is_null($uidvalid) || - ($uidvalid == $this->_mbox[$mailbox]['d']['uidvalid'])) { - return; - } - $this->deleteMailbox($mailbox); - } - - $this->_mbox[$mailbox] = array( - // Metadata storage - // By default includes UIDVALIDITY of mailbox. - 'd' => array('uidvalid' => $uidvalid), - // List of UIDs - 'u' => new Horde_Imap_Client_Ids() - ); - } - - /** - * Load UIDs by regenerating from the cache. - * - * @param string $mailbox The mailbox to load. - * @param array $uids The UIDs to load. - * @param integer $uidvalid The IMAP uidvalidity value of the mailbox. - */ - protected function _loadUids($mailbox, $uids, $uidvalid = null) - { - if (!isset($this->_data[$mailbox])) { - $this->_data[$mailbox] = array(); - } - - $this->_loadMailbox($mailbox, $uidvalid); - - if (empty($uids)) { - return; - } - - $ptr = &$this->_data[$mailbox]; - - $load = array_flip( - array_diff_key( - $this->_getMsgCids( - $mailbox, - array_unique(array_intersect($this->_mbox[$mailbox]['u']->ids, $uids)) - ), - $this->_data[$mailbox] - ) - ); - - foreach (array_filter($this->_hash->get(array_keys($load))) as $key => $val) { - $ptr[$load[$key]] = $val; - } - } - - /** - * Create the unique ID used to store the mailbox data in the cache. - * - * @param string $mailbox The mailbox to cache. - * - * @return string The cache ID. - */ - protected function _getCid($mailbox) - { - return implode(self::CID_SEPARATOR, array( - 'horde_imap_client', - $this->_params['username'], - $mailbox, - $this->_params['hostspec'], - $this->_params['port'] - )); - } - - /** - * Return a list of cache IDs for mailbox/UID pairs. - * - * @param string $mailbox The mailbox to cache. - * @param array $ids The UID list. - * - * @return array List of UIDs => cache IDs. - */ - protected function _getMsgCids($mailbox, $ids) - { - $cid = $this->_getCid($mailbox); - $out = array(); - - foreach ($ids as $val) { - $out[$val] = $cid . self::CID_SEPARATOR . $val; - } - - return $out; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Mongo.php b/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Mongo.php deleted file mode 100644 index adcf2ac5fa6..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Mongo.php +++ /dev/null @@ -1,440 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Cache_Backend_Mongo -extends Horde_Imap_Client_Cache_Backend -implements Horde_Mongo_Collection_Index -{ - /** Mongo collection names. */ - const BASE = 'horde_imap_client_cache_data'; - const MD = 'horde_imap_client_cache_metadata'; - const MSG = 'horde_imap_client_cache_message'; - - /** Mongo field names: BASE collection. */ - const BASE_HOSTSPEC = 'hostspec'; - const BASE_MAILBOX = 'mailbox'; - const BASE_MODIFIED = 'modified'; - const BASE_PORT = 'port'; - const BASE_UID = 'data'; - const BASE_USERNAME = 'username'; - - /** Mongo field names: MD collection. */ - const MD_DATA = 'data'; - const MD_FIELD = 'field'; - const MD_UID = 'uid'; - - /** Mongo field names: MSG collection. */ - const MSG_DATA = 'data'; - const MSG_MSGUID = 'msguid'; - const MSG_UID = 'uid'; - - /** - * The MongoDB object for the cache data. - * - * @var MongoDB - */ - protected $_db; - - /** - * The list of indices. - * - * @var array - */ - protected $_indices = array( - self::BASE => array( - 'base_index_1' => array( - self::BASE_HOSTSPEC => 1, - self::BASE_MAILBOX => 1, - self::BASE_PORT => 1, - self::BASE_USERNAME => 1, - ) - ), - self::MSG => array( - 'msg_index_1' => array( - self::MSG_MSGUID => 1, - self::MSG_UID => 1 - ) - ) - ); - - /** - * Constructor. - * - * @param array $params Configuration parameters: - *
-     *   - REQUIRED parameters:
-     *     - mongo_db: (Horde_Mongo_Client) A MongoDB client object.
-     * 
- */ - public function __construct(array $params = array()) - { - if (!isset($params['mongo_db'])) { - throw new InvalidArgumentException('Missing mongo_db parameter.'); - } - - parent::__construct($params); - } - - /** - */ - protected function _initOb() - { - $this->_db = $this->_params['mongo_db']->selectDB(null); - } - - /** - */ - public function get($mailbox, $uids, $fields, $uidvalid) - { - $this->getMetaData($mailbox, $uidvalid, array('uidvalid')); - - if (!($uid = $this->_getUid($mailbox))) { - return array(); - } - - $out = array(); - $query = array( - self::MSG_MSGUID => array('$in' => array_map('strval', $uids)), - self::MSG_UID => $uid - ); - - try { - $cursor = $this->_db->selectCollection(self::MSG)->find( - $query, - array(self::MSG_DATA => true, self::MSG_MSGUID => true) - ); - foreach ($cursor as $val) { - try { - $out[$val[self::MSG_MSGUID]] = $this->_value($val[self::MSG_DATA]); - } catch (Exception $e) {} - } - } catch (MongoException $e) {} - - return $out; - } - - /** - */ - public function getCachedUids($mailbox, $uidvalid) - { - $this->getMetaData($mailbox, $uidvalid, array('uidvalid')); - - if (!($uid = $this->_getUid($mailbox))) { - return array(); - } - - $out = array(); - $query = array( - self::MSG_UID => $uid - ); - - try { - $cursor = $this->_db->selectCollection(self::MSG)->find( - $query, array(self::MSG_MSGUID => true) - ); - foreach ($cursor as $val) { - $out[] = $val[self::MSG_MSGUID]; - } - } catch (MongoException $e) {} - - return $out; - } - - /** - */ - public function set($mailbox, $data, $uidvalid) - { - if ($uid = $this->_getUid($mailbox)) { - $res = $this->get($mailbox, array_keys($data), array(), $uidvalid); - } else { - $res = array(); - $uid = $this->_createUid($mailbox); - } - - $coll = $this->_db->selectCollection(self::MSG); - - foreach ($data as $key => $val) { - try { - if (isset($res[$key])) { - $coll->update(array( - self::MSG_MSGUID => strval($key), - self::MSG_UID => $uid - ), array( - self::MSG_DATA => $this->_value(array_merge($res[$key], $val)), - self::MSG_MSGUID => strval($key), - self::MSG_UID => $uid - )); - } else { - $doc = array( - self::MSG_DATA => $this->_value($val), - self::MSG_MSGUID => strval($key), - self::MSG_UID => $uid - ); - $coll->insert($doc); - } - } catch (MongoException $e) {} - } - - /* Update modified time. */ - try { - $this->_db->selectCollection(self::BASE)->update( - array(self::BASE_UID => $uid), - array(self::BASE_MODIFIED => time()) - ); - } catch (MongoException $e) {} - - /* Update uidvalidity. */ - $this->setMetaData($mailbox, array('uidvalid' => $uidvalid)); - } - - /** - */ - public function getMetaData($mailbox, $uidvalid, $entries) - { - if (!($uid = $this->_getUid($mailbox))) { - return array(); - } - - $out = array(); - $query = array( - self::MD_UID => $uid - ); - - if (!empty($entries)) { - $entries[] = 'uidvalid'; - $query[self::MD_FIELD] = array( - '$in' => array_unique($entries) - ); - } - - try { - $cursor = $this->_db->selectCollection(self::MD)->find( - $query, - array(self::MD_DATA => true, self::MD_FIELD => true) - ); - foreach ($cursor as $val) { - try { - $out[$val[self::MD_FIELD]] = $this->_value($val[self::MD_DATA]); - } catch (Exception $e) {} - } - - if (is_null($uidvalid) || - !isset($out['uidvalid']) || - ($out['uidvalid'] == $uidvalid)) { - return $out; - } - - $this->deleteMailbox($mailbox); - } catch (MongoException $e) {} - - return array(); - } - - /** - */ - public function setMetaData($mailbox, $data) - { - if (!($uid = $this->_getUid($mailbox))) { - $uid = $this->_createUid($mailbox); - } - - $coll = $this->_db->selectCollection(self::MD); - - foreach ($data as $key => $val) { - try { - $coll->update( - array( - self::MD_FIELD => $key, - self::MD_UID => $uid - ), - array( - self::MD_DATA => $this->_value($val), - self::MD_FIELD => $key, - self::MD_UID => $uid - ), - array('upsert' => true) - ); - } catch (MongoException $e) {} - } - } - - /** - */ - public function deleteMsgs($mailbox, $uids) - { - if (!empty($uids) && ($uid = $this->_getUid($mailbox))) { - try { - $this->_db->selectCollection(self::MSG)->remove(array( - self::MSG_MSGUID => array( - '$in' => array_map('strval', $uids) - ), - self::MSG_UID => $uid - )); - } catch (MongoException $e) {} - } - } - - /** - */ - public function deleteMailbox($mailbox) - { - if (!($uid = $this->_getUid($mailbox))) { - return; - } - - foreach (array(self::BASE, self::MD, self::MSG) as $val) { - try { - $this->_db->selectCollection($val) - ->remove(array('uid' => $uid)); - } catch (MongoException $e) {} - } - } - - /** - */ - public function clear($lifetime) - { - if (is_null($lifetime)) { - foreach (array(self::BASE, self::MD, self::MSG) as $val) { - $this->_db->selectCollection($val)->drop(); - } - return; - } - - $query = array( - self::BASE_MODIFIED => array('$lt' => (time() - $lifetime)) - ); - $uids = array(); - - try { - $cursor = $this->_db->selectCollection(self::BASE)->find($query); - foreach ($cursor as $val) { - $uids[] = strval($val['_id']); - } - } catch (MongoException $e) {} - - if (empty($uids)) { - return; - } - - foreach (array(self::BASE, self::MD, self::MSG) as $val) { - try { - $this->_db->selectCollection($val) - ->remove(array('uid' => array('$in' => $uids))); - } catch (MongoException $e) {} - } - } - - /** - * Return the UID for a mailbox/user/server combo. - * - * @param string $mailbox Mailbox name. - * - * @return string UID from base table. - */ - protected function _getUid($mailbox) - { - $query = array( - self::BASE_HOSTSPEC => $this->_params['hostspec'], - self::BASE_MAILBOX => $mailbox, - self::BASE_PORT => $this->_params['port'], - self::BASE_USERNAME => $this->_params['username'] - ); - - try { - if ($result = $this->_db->selectCollection(self::BASE)->findOne($query)) { - return strval($result['_id']); - } - } catch (MongoException $e) {} - - return null; - } - - /** - * Create and return the UID for a mailbox/user/server combo. - * - * @param string $mailbox Mailbox name. - * - * @return string UID from base table. - */ - protected function _createUid($mailbox) - { - $doc = array( - self::BASE_HOSTSPEC => $this->_params['hostspec'], - self::BASE_MAILBOX => $mailbox, - self::BASE_PORT => $this->_params['port'], - self::BASE_USERNAME => $this->_params['username'] - ); - $this->_db->selectCollection(self::BASE)->insert($doc); - - return $this->_getUid($mailbox); - } - - /** - * Convert data from/to storage format. - * - * @param mixed|MongoBinData $data The data object. - * - * @return mixed|MongoBinData The converted data. - */ - protected function _value($data) - { - static $compress; - - if (!isset($compress)) { - $compress = new Horde_Compress_Fast(); - } - - return ($data instanceof MongoBinData) - ? @unserialize($compress->decompress($data->bin)) - : new MongoBinData( - $compress->compress(serialize($data)), MongoBinData::BYTE_ARRAY - ); - } - - /* Horde_Mongo_Collection_Index methods. */ - - /** - */ - public function checkMongoIndices() - { - foreach ($this->_indices as $key => $val) { - if (!$this->_params['mongo_db']->checkIndices($key, $val)) { - return false; - } - } - - return true; - } - - /** - */ - public function createMongoIndices() - { - foreach ($this->_indices as $key => $val) { - $this->_params['mongo_db']->createIndices($key, $val); - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Null.php b/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Null.php deleted file mode 100644 index 242176d33b5..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Cache/Backend/Null.php +++ /dev/null @@ -1,79 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Cache_Backend_Null -extends Horde_Imap_Client_Cache_Backend -{ - /** - */ - public function get($mailbox, $uids, $fields, $uidvalid) - { - return array(); - } - - /** - */ - public function getCachedUids($mailbox, $uidvalid) - { - return array(); - } - - /** - */ - public function set($mailbox, $data, $uidvalid) - { - } - - /** - */ - public function getMetaData($mailbox, $uidvalid, $entries) - { - return array( - 'uidvalid' => 0 - ); - } - - /** - */ - public function setMetaData($mailbox, $data) - { - } - - /** - */ - public function deleteMsgs($mailbox, $uids) - { - } - - /** - */ - public function deleteMailbox($mailbox) - { - } - - /** - */ - public function clear($lifetime) - { - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Acl.php b/lib/horde/framework/Horde/Imap/Client/Data/Acl.php deleted file mode 100644 index 69e8e51139e..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Acl.php +++ /dev/null @@ -1,188 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Acl extends Horde_Imap_Client_Data_AclCommon implements ArrayAccess, IteratorAggregate, Serializable -{ - /** - * ACL rights. - * - * @var array - */ - protected $_rights; - - /** - * Constructor. - * - * @param string $rights The rights (see RFC 4314 [2.1]). - */ - public function __construct($rights = '') - { - $this->_rights = str_split($rights); - $this->_normalize(); - } - - /** - * String representation of the ACL. - * - * @return string String representation (RFC 4314 compliant). - */ - public function __toString() - { - return implode('', $this->_rights); - } - - /** - * Computes the difference to another rights string. - * Virtual rights are ignored. - * - * @param string $rights The rights to compute against. - * - * @return array Two element array: added and removed. - */ - public function diff($rights) - { - $rlist = array_diff(str_split($rights), array_keys($this->_virtual)); - - return array( - 'added' => implode('', array_diff($rlist, $this->_rights)), - 'removed' => implode('', array_diff($this->_rights, $rlist)) - ); - } - - /** - * Normalize virtual rights (see RFC 4314 [2.1.1]). - */ - protected function _normalize() - { - /* Clients conforming to RFC 4314 MUST ignore the virtual ACL_CREATE - * and ACL_DELETE rights. See RFC 4314 [2.1]. However, we still need - * to handle these rights when dealing with RFC 2086 servers since - * we are abstracting out use of ACL_CREATE/ACL_DELETE to their - * component RFC 4314 rights. */ - foreach ($this->_virtual as $key => $val) { - foreach ($val as $right) { - if ($this[$right]) { - foreach (array_keys($this->_virtual) as $virtual) { - unset($this[$virtual]); - } - return; - } - } - } - foreach ($this->_virtual as $key => $val) { - if ($this[$key]) { - unset($this[$key]); - $this->_rights = array_unique(array_merge($this->_rights, $val)); - } - } - } - - /* ArrayAccess methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) - { - return $this[$offset]; - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - return in_array($offset, $this->_rights); - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - if ($value) { - if (!$this[$offset]) { - $this->_rights[] = $offset; - $this->_normalize(); - } - } elseif ($this[$offset]) { - if (isset($this->_virtual[$offset])) { - foreach ($this->_virtual[$offset] as $val) { - unset($this[$val]); - } - } - unset($this[$offset]); - } - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetUnset($offset) - { - $this->_rights = array_values(array_diff($this->_rights, array($offset))); - } - - /* IteratorAggregate method. */ - - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_rights); - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version changed.'); - } - $this->__unserialize($data); - } - - /** - * @return array - */ - public function __serialize() - { - return array( - 'rights' => $this->_rights - ); - } - - public function __unserialize(array $data) - { - $this->_rights = $data['rights']; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/AclCommon.php b/lib/horde/framework/Horde/Imap/Client/Data/AclCommon.php deleted file mode 100644 index 80c9a56f4a8..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/AclCommon.php +++ /dev/null @@ -1,72 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_AclCommon -{ - /** Constants for getString(). */ - const RFC_2086 = 1; - const RFC_4314 = 2; - - /** - * List of virtual rights (RFC 4314 [2.1.1]). - * - * @var array - */ - protected $_virtual = array( - Horde_Imap_Client::ACL_CREATE => array( - Horde_Imap_Client::ACL_CREATEMBOX, - Horde_Imap_Client::ACL_DELETEMBOX - ), - Horde_Imap_Client::ACL_DELETE => array( - Horde_Imap_Client::ACL_DELETEMSGS, - // Don't put this first - we do checks on the existence of the - // first element in this array to determine the RFC type, and this - // is duplicate of right contained in ACL_CREATE. - Horde_Imap_Client::ACL_DELETEMBOX, - Horde_Imap_Client::ACL_EXPUNGE - ) - ); - - /** - * Returns the raw string to use in IMAP server calls. - * - * @param integer $type The RFC type to use (RFC_* constant). - * - * @return string The string representation of the ACL. - */ - public function getString($type = self::RFC_4314) - { - $acl = strval($this); - - if ($type == self::RFC_2086) { - foreach ($this->_virtual as $key => $val) { - $acl = str_replace($val, '', $acl, $count); - if ($count) { - $acl .= $key; - } - } - } - - return $acl; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/AclNegative.php b/lib/horde/framework/Horde/Imap/Client/Data/AclNegative.php deleted file mode 100644 index 62e8828c8d3..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/AclNegative.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_AclNegative extends Horde_Imap_Client_Data_Acl -{ -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/AclRights.php b/lib/horde/framework/Horde/Imap/Client/Data/AclRights.php deleted file mode 100644 index 2a9c0d181be..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/AclRights.php +++ /dev/null @@ -1,231 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_AclRights extends Horde_Imap_Client_Data_AclCommon implements ArrayAccess, Iterator, Serializable -{ - /** - * ACL optional rights. - * - * @var array - */ - protected $_optional = array(); - - /** - * ACL required rights. - * - * @var array - */ - protected $_required = array(); - - /** - * Constructor. - * - * @param array $required The required rights (see RFC 4314 [2.1]). - * @param array $optional The optional rights (see RFC 4314 [2.1]). - */ - public function __construct(array $required = array(), - array $optional = array()) - { - $this->_required = $required; - - foreach ($optional as $val) { - foreach (str_split($val) as $right) { - $this->_optional[$right] = $val; - } - } - - $this->_normalize(); - } - - /** - * String representation of the ACL. - * - * @return string String representation (RFC 4314 compliant). - * - */ - public function __toString() - { - return implode('', array_keys(array_flip(array_merge(array_values($this->_required), array_keys($this->_optional))))); - } - - /** - * Normalize virtual rights (see RFC 4314 [2.1.1]). - */ - protected function _normalize() - { - /* Clients conforming to RFC 4314 MUST ignore the virtual ACL_CREATE - * and ACL_DELETE rights. See RFC 4314 [2.1]. However, we still need - * to handle these rights when dealing with RFC 2086 servers since - * we are abstracting out use of ACL_CREATE/ACL_DELETE to their - * component RFC 4314 rights. */ - foreach ($this->_virtual as $key => $val) { - if (isset($this->_optional[$key])) { - unset($this->_optional[$key]); - foreach ($val as $val2) { - $this->_optional[$val2] = implode('', $val); - } - } elseif (($pos = array_search($key, $this->_required)) !== false) { - unset($this->_required[$pos]); - $this->_required = array_unique(array_merge($this->_required, $val)); - } - } - } - - /* ArrayAccess methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) - { - return (bool)$this[$offset]; - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - if (isset($this->_optional[$offset])) { - return $this->_optional[$offset]; - } - - $pos = array_search($offset, $this->_required); - - return ($pos === false) - ? null - : $this->_required[$pos]; - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - $this->_optional[$offset] = $value; - $this->_normalize(); - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetUnset($offset) - { - unset($this->_optional[$offset]); - $this->_required = array_values(array_diff($this->_required, array($offset))); - - if (isset($this->_virtual[$offset])) { - foreach ($this->_virtual[$offset] as $val) { - unset($this[$val]); - } - } - } - - /* Iterator methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function current() - { - $val = current($this->_required); - return is_null($val) - ? current($this->_optional) - : $val; - } - - /** - */ - #[ReturnTypeWillChange] - public function key() - { - $key = key($this->_required); - return is_null($key) - ? key($this->_optional) - : $key; - } - - /** - */ - #[ReturnTypeWillChange] - public function next() - { - if (key($this->_required) === null) { - next($this->_optional); - } else { - next($this->_required); - } - } - - /** - */ - #[ReturnTypeWillChange] - public function rewind() - { - reset($this->_required); - reset($this->_optional); - } - - /** - */ - #[ReturnTypeWillChange] - public function valid() - { - return ((key($this->_required) !== null) || - (key($this->_optional) !== null)); - - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version changed.'); - } - $this->__unserialize($data); - } - - /** - * @return array - */ - public function __serialize() - { - return [$this->_required, $this->_optional]; - } - - public function __unserialize(array $data) - { - list($this->_required, $this->_optional) = $data; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/BaseSubject.php b/lib/horde/framework/Horde/Imap/Client/Data/BaseSubject.php deleted file mode 100644 index 0cb0794338e..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/BaseSubject.php +++ /dev/null @@ -1,231 +0,0 @@ - - * - * See the enclosed file LICENSE for license information (LGPL). If you - * did not receive this file, see http://www.horde.org/licenses/lgpl21. - * - * @category Horde - * @copyright 2002-2008 Timo Sirainen - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ - -/** - * Determines the "base subject" of a string (RFC 5256 [2.1]). - * - * @author Timo Sirainen - * @author Michael Slusarz - * @category Horde - * @copyright 2002-2008 Timo Sirainen - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_BaseSubject -{ - /** - * The base subject. - * - * @var string - */ - protected $_subject; - - /** - * 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); - } - - /** - * Return the "base subject" defined in RFC 5256 [2.1]. - * - * @return string The base subject. - */ - public function __toString() - { - return $this->_subject; - } - - /** - * Remove all prefix text of the subject that matches the subj-leader - * ABNF. - * - * @param string &$str The subject string. - * @param boolean $keepblob Remove blob information? - * - * @return boolean True if string was altered. - */ - protected function _removeSubjLeader(&$str, $keepblob = false) - { - $ret = false; - - if (!strlen($str)) { - return $ret; - } - - if ($len = strspn($str, " \t")) { - $str = substr($str, $len); - $ret = true; - } - - $i = 0; - - if (!$keepblob) { - while (isset($str[$i]) && ($str[$i] === '[')) { - if (($i = $this->_removeBlob($str, $i)) === false) { - return $ret; - } - } - } - - if (stripos($str, 're', $i) === 0) { - $i += 2; - } elseif (stripos($str, 'fw', $i) === 0) { - $i += (stripos($str, 'fwd', $i) === 0) ? 3 : 2; - } else { - return $ret; - } - - $i += strspn($str, " \t", $i); - - if (!$keepblob) { - while (isset($str[$i]) && ($str[$i] === '[')) { - if (($i = $this->_removeBlob($str, $i)) === false) { - return $ret; - } - } - } - - if (!isset($str[$i]) || ($str[$i] !== ':')) { - return $ret; - } - - $str = substr($str, ++$i); - - return true; - } - - /** - * Remove "[...]" text. - * - * @param string $str The subject string. - * @param integer $i Current position. - * - * @return boolean|integer False if blob was not found, otherwise the - * string position of the first non-blob char. - */ - protected function _removeBlob($str, $i) - { - if ($str[$i] !== '[') { - return false; - } - - ++$i; - - for ($cnt = strlen($str); $i < $cnt; ++$i) { - if ($str[$i] === ']') { - break; - } - - if ($str[$i] === '[') { - return false; - } - } - - if ($i === ($cnt - 1)) { - return false; - } - - ++$i; - - if ($str[$i] === ' ') { - ++$i; - } - - return $i; - } - - /** - * Remove "[...]" text if it doesn't result in the subject becoming - * empty. - * - * @param string &$str The subject string. - * - * @return boolean True if string was altered. - */ - protected function _removeBlobWhenNonempty(&$str) - { - if ($str && - ($str[0] === '[') && - (($i = $this->_removeBlob($str, 0)) !== false) && - ($i !== strlen($str))) { - $str = substr($str, $i); - return true; - } - - return false; - } - - /** - * Remove a "[fwd: ... ]" string. - * - * @param string &$str The subject string. - * - * @return boolean True if string was altered. - */ - protected function _removeSubjFwdHdr(&$str) - { - if ((stripos($str, '[fwd:') !== 0) || (substr($str, -1) !== ']')) { - return false; - } - - $str = substr($str, 5, -1); - return true; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Capability.php b/lib/horde/framework/Horde/Imap/Client/Data/Capability.php deleted file mode 100644 index e5c1eb97648..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Capability.php +++ /dev/null @@ -1,234 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.24.0 - */ -class Horde_Imap_Client_Data_Capability -implements Serializable, SplSubject -{ - /** - * Capability data. - * - * @var array - */ - protected $_data = array(); - - /** - * Observers. - * - * @var array - */ - protected $_observers = array(); - - /** - * Add a capability (and optional parameters). - * - * @param string $capability The capability to add. - * @param mixed $params A parameter (or array of parameters) to add. - */ - public function add($capability, $params = null) - { - $capability = Horde_String::upper($capability); - - if (is_null($params)) { - if (isset($this->_data[$capability])) { - return; - } - $params = true; - } else { - if (!is_array($params)) { - $params = array($params); - } - $params = array_map('Horde_String::upper', $params); - - if (isset($this->_data[$capability]) && - is_array($this->_data[$capability])) { - $params = array_merge($this->_data[$capability], $params); - } - } - - $this->_data[$capability] = $params; - $this->notify(); - } - - /** - * Remove a capability. - * - * @param string $capability The capability to remove. - * @param string $params A parameter (or array of parameters) to - * remove from the capability. - */ - public function remove($capability, $params = null) - { - $capability = Horde_String::upper($capability); - - if (is_null($params)) { - unset($this->_data[$capability]); - } elseif (isset($this->_data[$capability])) { - if (!is_array($params)) { - $params = array($params); - } - $params = array_map('Horde_String::upper', $params); - - $this->_data[$capability] = is_array($this->_data[$capability]) - ? array_diff($this->_data[$capability], $params) - : array(); - - if (empty($this->_data[$capability])) { - unset($this->_data[$capability]); - } - } - - $this->notify(); - } - - /** - * Returns whether the server supports the given capability. - * - * @param string $capability The capability string to query. - * @param string $parameter If set, require the parameter to exist. - * - * @return boolean True if the capability (and parameter) exist. - */ - public function query($capability, $parameter = null) - { - $capability = Horde_String::upper($capability); - - if (!isset($this->_data[$capability])) { - return false; - } - - return is_null($parameter) ?: - (is_array($this->_data[$capability]) && - in_array(Horde_String::upper($parameter), $this->_data[$capability])); - } - - /** - * Return the list of parameters for an extension. - * - * @param string $capability The capability string to query. - * - * @return array An array of parameters if the extension exists and - * supports parameters. Otherwise, an empty array. - */ - public function getParams($capability) - { - return ($this->query($capability) && is_array($out = $this->_data[Horde_String::upper($capability)])) - ? $out - : array(); - } - - /** - * Is the extension enabled? - * - * @param string $capability The extension (+ parameter) to query. If - * null, returns all enabled extensions. - * - * @return mixed If $capability is null, return all enabled extensions. - * Otherwise, true if the extension (+ parameter) is - * enabled. - */ - public function isEnabled($capability = null) - { - return is_null($capability) - ? array() - : false; - } - - /** - * Returns the raw data. - * - * @deprecated - * - * @return array Capability data. - */ - public function toArray() - { - return $this->_data; - } - - /* SplSubject methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function attach(SplObserver $observer) - { - $this->detach($observer); - $this->_observers[] = $observer; - } - - /** - */ - #[ReturnTypeWillChange] - public function detach(SplObserver $observer) - { - if (($key = array_search($observer, $this->_observers, true)) !== false) { - unset($this->_observers[$key]); - } - } - - /** - * Notification is triggered internally whenever the object's internal - * data storage is altered. - */ - #[ReturnTypeWillChange] - public function notify() - { - foreach ($this->_observers as $val) { - $val->update($this); - } - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version change.'); - } - $this->__unserialize(); - } - - /** - * @return array - */ - public function __serialize() - { - return $this->_data; - } - - public function __unserialize(array $data) - { - $this->_data = $data; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Capability/Imap.php b/lib/horde/framework/Horde/Imap/Client/Data/Capability/Imap.php deleted file mode 100644 index 028874afcff..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Capability/Imap.php +++ /dev/null @@ -1,117 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.24.0 - * - * @property-read integer $cmdlength Allowable command length (in octets). - */ -class Horde_Imap_Client_Data_Capability_Imap -extends Horde_Imap_Client_Data_Capability -{ - /** - * The list of enabled extensions. - * - * @var array - */ - protected $_enabled = array(); - - /** - */ - public function __get($name) - { - switch ($name) { - case 'cmdlength': - /* RFC 2683 [3.2.1.5] originally recommended that lines should - * be limited to "approximately 1000 octets". However, servers - * should allow a command line of at least "8000 octets". - * RFC 7162 [4] updates the recommendation to 8192 octets. - * As a compromise, assume all modern IMAP servers handle - * ~2000 octets and, if CONDSTORE/QRESYNC is supported, assume - * they can handle ~8000 octets. (Don't need dependency support - * checks here - the simple presence of CONDSTORE/QRESYNC is - * enough to trigger.) */ - return (isset($this->_data['CONDSTORE']) || isset($this->_data['QRESYNC'])) - ? 8000 - : 2000; - } - } - - /** - */ - public function query($capability, $parameter = null) - { - if (parent::query($capability, $parameter)) { - return true; - } - - switch (Horde_String::upper($capability)) { - case 'CONDSTORE': - case 'ENABLE': - /* RFC 7162 [3.2.3] - QRESYNC implies CONDSTORE and ENABLE. */ - return (is_null($parameter) && $this->query('QRESYNC')); - - case 'UTF8': - /* RFC 6855 [3] - UTF8=ONLY implies UTF8=ACCEPT. */ - return ((Horde_String::upper($parameter) === 'ACCEPT') && - $this->query('UTF8', 'ONLY')); - } - - return false; - } - - /** - */ - public function isEnabled($capability = null) - { - return is_null($capability) - ? $this->_enabled - : in_array(Horde_String::upper($capability), $this->_enabled); - } - - /** - * Set a capability as enabled/disabled. - * - * @param array $capability A capability (+ parameter). - * @param boolean $enable If true, enables the capability. - */ - public function enable($capability, $enable = true) - { - $capability = Horde_String::upper($capability); - $enabled = $this->isEnabled($capability); - - if ($enable && !$enabled) { - switch ($capability) { - case 'QRESYNC': - /* RFC 7162 [3.2.3] - Enabling QRESYNC also implies enabling - * of CONDSTORE. */ - $this->enable('CONDSTORE'); - break; - } - - $this->_enabled[] = $capability; - $this->notify(); - } elseif (!$enable && $enabled) { - $this->_enabled = array_diff($this->_enabled, array($capability)); - $this->notify(); - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Envelope.php b/lib/horde/framework/Horde/Imap/Client/Data/Envelope.php deleted file mode 100644 index 098b2e4d198..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Envelope.php +++ /dev/null @@ -1,238 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * - * @todo $date should return null if it doesn't exist. - * - * @property Horde_Mail_Rfc822_List $bcc Bcc address(es). - * @property Horde_Mail_Rfc822_List $cc Cc address(es). - * @property Horde_Imap_Client_DateTime $date Message date. - * @property Horde_Mail_Rfc822_List $from From address(es). - * @property string $in_reply_to Message-ID of the message replied to. - * @property string $message_id Message-ID of the message. - * @property Horde_Mail_Rfc822_List $reply_to Reply-to address(es). - * @property Horde_Mail_Rfc822_List $sender Sender address. - * @property string $subject Subject. - * @property Horde_Mail_Rfc822_List $to To address(es). - */ -class Horde_Imap_Client_Data_Envelope implements Serializable -{ - /* Serializable version. */ - const VERSION = 3; - - /** - * Data object. - * - * @var Horde_Mime_Headers - */ - protected $_data; - - /** - * Constructor. - * - * @var array $data An array of property names (keys) and values to set - * in this object. - */ - public function __construct(array $data = array()) - { - $this->_data = new Horde_Mime_Headers(); - - foreach ($data as $key => $val) { - $this->$key = $val; - } - } - - /** - */ - public function __get($name) - { - $name = $this->_normalizeProperty($name); - - switch ($name) { - case 'bcc': - case 'cc': - case 'from': - case 'reply-to': - case 'sender': - case 'to': - if ($h = $this->_data[$name]) { - return $h->getAddressList(true); - } - - if (in_array($name, array('sender', 'reply-to'))) { - return $this->from; - } - break; - - case 'date': - if ($val = $this->_data['date']) { - return new Horde_Imap_Client_DateTime($val->value); - } - break; - - case 'in-reply-to': - case 'message-id': - case 'subject': - if ($val = $this->_data[$name]) { - return $val->value; - } - break; - } - - // Default values. - switch ($name) { - case 'bcc': - case 'cc': - case 'from': - case 'to': - return new Horde_Mail_Rfc822_List(); - - case 'date': - return new Horde_Imap_Client_DateTime(); - - case 'in-reply-to': - case 'message-id': - case 'subject': - return ''; - } - - return null; - } - - /** - */ - public function __set($name, $value) - { - if (!strlen($value)) { - return; - } - - $name = $this->_normalizeProperty($name); - - switch ($name) { - case 'bcc': - case 'cc': - case 'date': - case 'from': - case 'in-reply-to': - case 'message-id': - case 'reply-to': - case 'sender': - case 'subject': - case 'to': - switch ($name) { - case 'from': - if ($this->reply_to->match($value)) { - unset($this->_data['reply-to']); - } - if ($this->sender->match($value)) { - unset($this->_data['sender']); - } - break; - - case 'reply-to': - case 'sender': - if ($this->from->match($value)) { - unset($this->_data[$name]); - return; - } - break; - } - - $this->_data->addHeader($name, $value); - break; - } - } - - /** - */ - public function __isset($name) - { - $name = $this->_normalizeProperty($name); - - switch ($name) { - case 'reply-to': - case 'sender': - if (isset($this->_data[$name])) { - return true; - } - $name = 'from'; - break; - } - - return isset($this->_data[$name]); - } - - /** - */ - protected function _normalizeProperty($name) - { - switch ($name) { - case 'in_reply_to': - return 'in-reply-to'; - - case 'message_id': - return 'message-id'; - - case 'reply_to': - return 'reply-to'; - } - - return $name; - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $this->__unserialize(@unserialize($data)); - } - - /** - * @return array - */ - public function __serialize() - { - return array( - 'd' => $this->_data, - 'v' => self::VERSION, - ); - } - - public function __unserialize(array $data) - { - if (empty($data['v']) || $data['v'] != self::VERSION) { - throw new Exception('Cache version change'); - } - - $this->_data = $data['d']; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Fetch.php b/lib/horde/framework/Horde/Imap/Client/Data/Fetch.php deleted file mode 100644 index 458da659c0c..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Fetch.php +++ /dev/null @@ -1,666 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Fetch -{ - /** Header formatting constants. */ - const HEADER_PARSE = 1; - const HEADER_STREAM = 2; - - /** - * Internal data array. - * - * @var array - */ - protected $_data = array(); - - /** - */ - public function __clone() - { - $this->_data = unserialize(serialize($this->_data)); - } - - /** - * Set the full message property. - * - * @param mixed $msg The full message text, as either a string or stream - * resource. - */ - public function setFullMsg($msg) - { - $this->_data[Horde_Imap_Client::FETCH_FULLMSG] = $this->_setMixed($msg); - } - - /** - * Returns the full message. - * - * @param boolean $stream Return as a stream? - * - * @return mixed The full text of the entire message. - */ - public function getFullMsg($stream = false) - { - return $this->_msgText( - $stream, - isset($this->_data[Horde_Imap_Client::FETCH_FULLMSG]) - ? $this->_data[Horde_Imap_Client::FETCH_FULLMSG] - : null - ); - } - - /** - * Set the message structure. - * - * @param Horde_Mime_Part $structure The base MIME part of the message. - */ - public function setStructure(Horde_Mime_Part $structure) - { - $this->_data[Horde_Imap_Client::FETCH_STRUCTURE] = $structure; - } - - /** - * Get the message structure. - * - * @return Horde_Mime_Part $structure The base MIME part of the message. - */ - public function getStructure() - { - return isset($this->_data[Horde_Imap_Client::FETCH_STRUCTURE]) - ? clone $this->_data[Horde_Imap_Client::FETCH_STRUCTURE] - : new Horde_Mime_Part(); - } - - /** - * Set a header entry. - * - * @param string $label The search label. - * @param mixed $data Either a Horde_Mime_Headers object or the raw - * header text. - */ - public function setHeaders($label, $data) - { - if ($data instanceof Horde_Stream) { - $data = $data->stream; - } - $this->_data[Horde_Imap_Client::FETCH_HEADERS][$label] = $data; - } - - /** - * Get a header entry. - * - * @param string $label The search label. - * @param integer $format The return format. If self::HEADER_PARSE, - * returns a Horde_Mime_Headers object. If - * self::HEADER_STREAM, returns a stream. - * Otherwise, returns header text. - * - * @return mixed See $format. - */ - public function getHeaders($label, $format = 0) - { - return $this->_getHeaders( - $label, - $format, - Horde_Imap_Client::FETCH_HEADERS - ); - } - - /** - * Set a header text entry. - * - * @param string $id The MIME ID. - * @param mixed $text The header text, as either a string or stream - * resource. - */ - public function setHeaderText($id, $text) - { - $this->_data[Horde_Imap_Client::FETCH_HEADERTEXT][$id] = $this->_setMixed($text); - } - - /** - * Get a header text entry. - * - * @param string $id The MIME ID. - * @param integer $format The return format. If self::HEADER_PARSE, - * returns a Horde_Mime_Headers object. If - * self::HEADER_STREAM, returns a stream. - * Otherwise, returns header text. - * - * @return mixed See $format. - */ - public function getHeaderText($id = 0, $format = 0) - { - return $this->_getHeaders( - $id, - $format, - Horde_Imap_Client::FETCH_HEADERTEXT - ); - } - - /** - * Set a MIME header entry. - * - * @param string $id The MIME ID. - * @param mixed $text The header text, as either a string or stream - * resource. - */ - public function setMimeHeader($id, $text) - { - $this->_data[Horde_Imap_Client::FETCH_MIMEHEADER][$id] = $this->_setMixed($text); - } - - /** - * Get a MIME header entry. - * - * @param string $id The MIME ID. - * @param integer $format The return format. If self::HEADER_PARSE, - * returns a Horde_Mime_Headers object. If - * self::HEADER_STREAM, returns a stream. - * Otherwise, returns header text. - * - * @return mixed See $format. - */ - public function getMimeHeader($id, $format = 0) - { - return $this->_getHeaders( - $id, - $format, - Horde_Imap_Client::FETCH_MIMEHEADER - ); - } - - /** - * Set a body part entry. - * - * @param string $id The MIME ID. - * @param mixed $text The body part text, as either a string or stream - * resource. - * @param string $decode Either '8bit', 'binary', or null. - */ - public function setBodyPart($id, $text, $decode = null) - { - $this->_data[Horde_Imap_Client::FETCH_BODYPART][$id] = array( - 'd' => $decode, - 't' => $this->_setMixed($text) - ); - } - - /** - * Get a body part entry. - * - * @param string $id The MIME ID. - * @param boolean $stream Return as a stream? - * - * @return mixed The full text of the body part. - */ - public function getBodyPart($id, $stream = false) - { - return $this->_msgText( - $stream, - isset($this->_data[Horde_Imap_Client::FETCH_BODYPART][$id]) - ? $this->_data[Horde_Imap_Client::FETCH_BODYPART][$id]['t'] - : null - ); - } - - /** - * Determines if/how a body part was MIME decoded on the server. - * - * @param string $id The MIME ID. - * - * @return string Either '8bit', 'binary', or null. - */ - public function getBodyPartDecode($id) - { - return isset($this->_data[Horde_Imap_Client::FETCH_BODYPART][$id]) - ? $this->_data[Horde_Imap_Client::FETCH_BODYPART][$id]['d'] - : null; - } - - /** - * Set the body part size for a body part. - * - * @param string $id The MIME ID. - * @param integer $size The size (in bytes). - */ - public function setBodyPartSize($id, $size) - { - $this->_data[Horde_Imap_Client::FETCH_BODYPARTSIZE][$id] = intval($size); - } - - /** - * Returns the body part size, if returned by the server. - * - * @param string $id The MIME ID. - * - * @return integer The body part size, in bytes. - */ - public function getBodyPartSize($id) - { - return isset($this->_data[Horde_Imap_Client::FETCH_BODYPARTSIZE][$id]) - ? $this->_data[Horde_Imap_Client::FETCH_BODYPARTSIZE][$id] - : null; - } - - /** - * Set a body text entry. - * - * @param string $id The MIME ID. - * @param mixed $text The body part text, as either a string or stream - * resource. - */ - public function setBodyText($id, $text) - { - $this->_data[Horde_Imap_Client::FETCH_BODYTEXT][$id] = $this->_setMixed($text); - } - - /** - * Get a body text entry. - * - * @param string $id The MIME ID. - * @param boolean $stream Return as a stream? - * - * @return mixed The full text of the body text. - */ - public function getBodyText($id = 0, $stream = false) - { - return $this->_msgText( - $stream, - isset($this->_data[Horde_Imap_Client::FETCH_BODYTEXT][$id]) - ? $this->_data[Horde_Imap_Client::FETCH_BODYTEXT][$id] - : null - ); - } - - /** - * Set envelope data. - * - * @param array $data The envelope data to pass to the Envelope object - * constructor, or an Envelope object. - */ - public function setEnvelope($data) - { - $this->_data[Horde_Imap_Client::FETCH_ENVELOPE] = is_array($data) - ? new Horde_Imap_Client_Data_Envelope($data) - : $data; - } - - /** - * Get envelope data. - * - * @return Horde_Imap_Client_Data_Envelope An envelope object. - */ - public function getEnvelope() - { - return isset($this->_data[Horde_Imap_Client::FETCH_ENVELOPE]) - ? clone $this->_data[Horde_Imap_Client::FETCH_ENVELOPE] - : new Horde_Imap_Client_Data_Envelope(); - } - - /** - * Set IMAP flags. - * - * @param array $flags An array of IMAP flags. - */ - public function setFlags(array $flags) - { - $this->_data[Horde_Imap_Client::FETCH_FLAGS] = array_map( - 'Horde_String::lower', - array_map('trim', $flags) - ); - } - - /** - * Get IMAP flags. - * - * @return array An array of IMAP flags (all flags in lowercase). - */ - public function getFlags() - { - return isset($this->_data[Horde_Imap_Client::FETCH_FLAGS]) - ? $this->_data[Horde_Imap_Client::FETCH_FLAGS] - : array(); - } - - /** - * Set IMAP internal date. - * - * @param mixed $date Either a Horde_Imap_Client_DateTime object or a - * date string. - */ - public function setImapDate($date) - { - $this->_data[Horde_Imap_Client::FETCH_IMAPDATE] = is_object($date) - ? $date - : new Horde_Imap_Client_DateTime($date); - } - - /** - * Get internal IMAP date. - * - * @return Horde_Imap_Client_DateTime A date object. - */ - public function getImapDate() - { - return isset($this->_data[Horde_Imap_Client::FETCH_IMAPDATE]) - ? clone $this->_data[Horde_Imap_Client::FETCH_IMAPDATE] - : new Horde_Imap_Client_DateTime(); - } - - /** - * Set message size. - * - * @param integer $size The size of the message, in bytes. - */ - public function setSize($size) - { - $this->_data[Horde_Imap_Client::FETCH_SIZE] = intval($size); - } - - /** - * Get message size. - * - * @return integer The size of the message, in bytes. - */ - public function getSize() - { - return isset($this->_data[Horde_Imap_Client::FETCH_SIZE]) - ? $this->_data[Horde_Imap_Client::FETCH_SIZE] - : 0; - } - - /** - * Set UID. - * - * @param integer $uid The message UID. - */ - public function setUid($uid) - { - $this->_data[Horde_Imap_Client::FETCH_UID] = intval($uid); - } - - /** - * Get UID. - * - * @return integer The message UID. - */ - public function getUid() - { - return isset($this->_data[Horde_Imap_Client::FETCH_UID]) - ? $this->_data[Horde_Imap_Client::FETCH_UID] - : null; - } - - /** - * Set message sequence number. - * - * @param integer $seq The message sequence number. - */ - public function setSeq($seq) - { - $this->_data[Horde_Imap_Client::FETCH_SEQ] = intval($seq); - } - - /** - * Get message sequence number. - * - * @return integer The message sequence number. - */ - public function getSeq() - { - return isset($this->_data[Horde_Imap_Client::FETCH_SEQ]) - ? $this->_data[Horde_Imap_Client::FETCH_SEQ] - : null; - } - - /** - * Set the modified sequence value for the message. - * - * @param integer $modseq The modseq value. - */ - public function setModSeq($modseq) - { - $this->_data[Horde_Imap_Client::FETCH_MODSEQ] = intval($modseq); - } - - /** - * Get the modified sequence value for the message. - * - * @return integer The modseq value. - */ - public function getModSeq() - { - return isset($this->_data[Horde_Imap_Client::FETCH_MODSEQ]) - ? $this->_data[Horde_Imap_Client::FETCH_MODSEQ] - : null; - } - - /** - * Set the internationalized downgraded status for the message. - * - * @since 2.11.0 - * - * @param boolean $downgraded True if at least one message component has - * been downgraded. - */ - public function setDowngraded($downgraded) - { - if ($downgraded) { - $this->_data[Horde_Imap_Client::FETCH_DOWNGRADED] = true; - } else { - unset($this->_data[Horde_Imap_Client::FETCH_DOWNGRADED]); - } - } - - /** - * Does the message contain internationalized downgraded data (i.e. it - * is a "surrogate" message)? - * - * @since 2.11.0 - * - * @return boolean True if at least one message components has been - * downgraded. - */ - public function isDowngraded() - { - return !empty($this->_data[Horde_Imap_Client::FETCH_DOWNGRADED]); - } - - /** - * Return the internal representation of the data. - * - * @return array The data array. - */ - public function getRawData() - { - return $this->_data; - } - - /** - * Merge a fetch object into this one. - * - * @param Horde_Imap_Client_Data_Fetch $data A fetch object. - */ - public function merge(Horde_Imap_Client_Data_Fetch $data) - { - $this->_data = array_replace_recursive( - $this->_data, - $data->getRawData() - ); - } - - /** - * Does this object containing cacheable data of the given type? - * - * @param integer $type The type to query. - * - * @return boolean True if the type is cacheable. - */ - public function exists($type) - { - return isset($this->_data[$type]); - } - - /** - * Does this object contain only default values for all fields? - * - * @return boolean True if object contains default data. - */ - public function isDefault() - { - return empty($this->_data); - } - - /** - * Return text representation of a field. - * - * @param boolean $stream Return as a stream? - * @param mixed $data The field data (string or resource) or null if - * field does not exist. - * - * @return mixed Requested text representation. - */ - protected function _msgText($stream, $data) - { - if ($data instanceof Horde_Stream) { - if ($stream) { - $data->rewind(); - return $data->stream; - } - return strval($data); - } - - if (is_resource($data)) { - rewind($data); - return $stream - ? $data - : stream_get_contents($data); - } - - if (!$stream) { - return strval($data); - } - - $tmp = fopen('php://temp', 'w+'); - - if (!is_null($data)) { - fwrite($tmp, $data); - rewind($tmp); - } - - return $tmp; - } - - /** - * Return representation of a header field. - * - * @param string $id The header id. - * @param integer $format The return format. If self::HEADER_PARSE, - * returns a Horde_Mime_Headers object. If - * self::HEADER_STREAM, returns a stream. - * Otherwise, returns header text. - * @param integer $key The array key where the data is stored in the - * internal array. - * - * @return mixed The data in the format specified by $format. - */ - protected function _getHeaders($id, $format, $key) - { - switch ($format) { - case self::HEADER_STREAM: - if (!isset($this->_data[$key][$id])) { - $data = null; - } elseif (is_object($this->_data[$key][$id])) { - switch ($key) { - case Horde_Imap_Client::FETCH_HEADERS: - $data = $this->_getHeaders($id, 0, $key); - break; - - case Horde_Imap_Client::FETCH_HEADERTEXT: - case Horde_Imap_Client::FETCH_MIMEHEADER: - $data = $this->_data[$key][$id]; - break; - } - } else { - $data = $this->_data[$key][$id]; - } - - return $this->_msgText(true, $data); - - case self::HEADER_PARSE: - if (!isset($this->_data[$key][$id])) { - return new Horde_Mime_Headers(); - } elseif (is_object($this->_data[$key][$id])) { - switch ($key) { - case Horde_Imap_Client::FETCH_HEADERS: - return clone $this->_data[$key][$id]; - - case Horde_Imap_Client::FETCH_HEADERTEXT: - case Horde_Imap_Client::FETCH_MIMEHEADER: - return Horde_Mime_Headers::parseHeaders($this->_data[$key][$id]); - } - } else { - $hdrs = $this->_getHeaders($id, self::HEADER_STREAM, $key); - $parsed = Horde_Mime_Headers::parseHeaders($hdrs); - fclose($hdrs); - return $parsed; - } - } - - if (!isset($this->_data[$key][$id])) { - return ''; - } - - if (is_object($this->_data[$key][$id])) { - switch ($key) { - case Horde_Imap_Client::FETCH_HEADERS: - return $this->_data[$key][$id]->toString( - array('nowrap' => true) - ); - - case Horde_Imap_Client::FETCH_HEADERTEXT: - case Horde_Imap_Client::FETCH_MIMEHEADER: - return strval($this->_data[$key][$id]); - } - } - - return $this->_msgText(false, $this->_data[$key][$id]); - } - - /** - * Converts mixed input (string or resource) to the correct internal - * representation. - * - * @param mixed $data Mixed data (string, resource, Horde_Stream object). - * - * @return mixed The internal representation of that data. - */ - protected function _setMixed($data) - { - return is_resource($data) - ? new Horde_Stream_Existing(array('stream' => $data)) - : $data; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Fetch/Pop3.php b/lib/horde/framework/Horde/Imap/Client/Data/Fetch/Pop3.php deleted file mode 100644 index 46cb3f9ac93..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Fetch/Pop3.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Fetch_Pop3 extends Horde_Imap_Client_Data_Fetch -{ - /** - * Set UID. - * - * @param string $uid The message UID. Unlike IMAP, this UID does not - * have to be an integer. - */ - public function setUid($uid) - { - $this->_data[Horde_Imap_Client::FETCH_UID] = strval($uid); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format.php b/lib/horde/framework/Horde/Imap/Client/Data/Format.php deleted file mode 100644 index b7e45e636cd..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format.php +++ /dev/null @@ -1,83 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format -{ - /** - * Data. - * - * @var mixed - */ - protected $_data; - - /** - * Constructor. - * - * @param mixed $data Data. - */ - public function __construct($data) - { - $this->_data = is_resource($data) - ? stream_get_contents($data, -1, 0) - : $data; - } - - /** - * Returns the string value of the raw data. - * - * @return string String value. - */ - public function __toString() - { - return strval($this->_data); - } - - /** - * Returns the raw data. - * - * @return mixed Raw data. - */ - public function getData() - { - return $this->_data; - } - - /** - * Returns the data formatted for output to the IMAP server. - * - * @return string IMAP escaped string. - */ - public function escape() - { - return strval($this); - } - - /** - * Verify the data. - * - * @throws Horde_Imap_Client_Data_Format_Exception - */ - public function verify() - { - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Astring.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Astring.php deleted file mode 100644 index 1007dd4ee52..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Astring.php +++ /dev/null @@ -1,32 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Astring extends Horde_Imap_Client_Data_Format_String -{ - /** - */ - public function quoted() - { - return $this->_filter->quoted || !$this->_data->length(); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Astring/Nonascii.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Astring/Nonascii.php deleted file mode 100644 index 61d3edcbfcc..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Astring/Nonascii.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.25.0 - */ -class Horde_Imap_Client_Data_Format_Astring_Nonascii -extends Horde_Imap_Client_Data_Format_Astring -implements Horde_Imap_Client_Data_Format_String_Support_Nonascii -{ -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Atom.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Atom.php deleted file mode 100644 index 111483394ac..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Atom.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Atom extends Horde_Imap_Client_Data_Format -{ - /** - */ - public function escape() - { - return strlen($this->_data) - ? parent::escape() - : '""'; - } - - /** - */ - public function verify() - { - if (strlen($this->_data) !== strlen($this->stripNonAtomCharacters())) { - throw new Horde_Imap_Client_Data_Format_Exception('Illegal character in IMAP atom.'); - } - } - - /** - * Strip out any characters that are not allowed in an IMAP atom. - * - * @return string The atom data disallowed characters removed. - */ - public function stripNonAtomCharacters() - { - return str_replace( - array('(', ')', '{', ' ', '%', '*', '"', '\\', ']'), - '', - preg_replace('/[^\x20-\x7e]/', '', $this->_data) - ); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Date.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Date.php deleted file mode 100644 index 172df01a27a..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Date.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Date extends Horde_Imap_Client_Data_Format -{ - /** - * Constructor. - * - * @param mixed $data Either a DateTime object, or a date format that - * can be converted to a DateTime object. - * - * @throws Exception - */ - public function __construct($data) - { - if (!($data instanceof DateTime)) { - $data = new Horde_Imap_Client_DateTime($data); - } - - parent::__construct($data); - } - - /** - */ - public function __toString() - { - return $this->_data->format('j-M-Y'); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/DateTime.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/DateTime.php deleted file mode 100644 index f9cdda77cbf..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/DateTime.php +++ /dev/null @@ -1,39 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_DateTime extends Horde_Imap_Client_Data_Format_Date -{ - /** - */ - public function __toString() - { - return $this->_data->format('j-M-Y H:i:s O'); - } - - /** - */ - public function escape() - { - return '"' . strval($this) . '"'; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Exception.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Exception.php deleted file mode 100644 index 1a93f72fea8..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Exception.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Exception extends Horde_Exception_Wrapped -{ -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Filter/Quote.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Filter/Quote.php deleted file mode 100644 index 1f652b2e312..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Filter/Quote.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Filter_Quote extends php_user_filter -{ - /** - * Has the initial quote been prepended? - * - * @var boolean - */ - protected $_prepend; - - /** - */ - #[ReturnTypeWillChange] - public function onCreate() - { - $this->_prepend = false; - } - - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function filter($in, $out, &$consumed, $closing) - { - if (!$this->_prepend) { - stream_bucket_append($out, stream_bucket_new($this->stream, '"')); - $this->_prepend = true; - } - - while ($bucket = stream_bucket_make_writeable($in)) { - $consumed += $bucket->datalen; - $bucket->data = addcslashes($bucket->data, '"\\'); - stream_bucket_append($out, $bucket); - } - - /* feof() call needed due to: - * http://news.php.net/php.internals/80363 */ - if ($closing || feof($this->stream)) { - stream_bucket_append($out, stream_bucket_new($this->stream, '"')); - } - - return PSFS_PASS_ON; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Filter/String.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Filter/String.php deleted file mode 100644 index 0ddd081da52..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Filter/String.php +++ /dev/null @@ -1,122 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Filter_String extends php_user_filter -{ - /** - * Skip status. - * - * @var boolean - */ - protected $_skip = false; - - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function onCreate() - { - $this->params->binary = false; - $this->params->literal = false; - $this->params->nonascii = false; - // no_quote_list is used below as a config option - $this->params->quoted = false; - - return true; - } - - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function filter($in, $out, &$consumed, $closing) - { - $p = $this->params; - - while ($bucket = stream_bucket_make_writeable($in)) { - if (!$this->_skip) { - $len = $bucket->datalen; - $str = $bucket->data; - - for ($i = 0; $i < $len; ++$i) { - $chr = ord($str[$i]); - - switch ($chr) { - case 0: // null - $p->binary = true; - $p->literal = true; - - // No need to scan input anymore. - $this->_skip = true; - break 2; - - case 10: // LF - case 13: // CR - $p->literal = true; - break; - - case 32: // SPACE - case 34: // " - case 40: // ( - case 41: // ) - case 92: // \ - case 123: // { - case 127: // DEL - // These are all invalid ATOM characters. - $p->quoted = true; - break; - - case 37: // % - case 42: // * - // These are not quoted if being used as wildcards. - if (empty($p->no_quote_list)) { - $p->quoted = true; - } - break; - - default: - if ($chr < 32) { - // CTL characters must be, at a minimum, quoted. - $p->quoted = true; - } elseif ($chr > 127) { - $p->nonascii = true; - // 8-bit chars must be in a literal. - $p->literal = true; - } - break; - } - } - } - - $consumed += $bucket->datalen; - stream_bucket_append($out, $bucket); - } - - if ($p->literal) { - $p->quoted = false; - } - - return PSFS_PASS_ON; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/List.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/List.php deleted file mode 100644 index 075fb1b5857..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/List.php +++ /dev/null @@ -1,108 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_List extends Horde_Imap_Client_Data_Format implements Countable, IteratorAggregate -{ - /** - * @see add() - */ - public function __construct($data = null) - { - parent::__construct(array()); - - if (!is_null($data)) { - $this->add($data); - } - } - - /** - * Add an element to the list. - * - * @param mixed $data The data element(s) to add. Either a - * Horde_Imap_Client_Data_Format object, a string - * value that will be treated as an IMAP atom, or - * an array (or iterable object) of objects to add. - * @param boolean $merge Merge the contents of any container objects, - * instead of adding the objects themselves? - * - * @return Horde_Imap_Client_Data_Format_List This object to allow for - * chainable calls (since - * 2.10.0). - */ - public function add($data, $merge = false) - { - if (is_array($data) || ($merge && ($data instanceof Traversable))) { - foreach ($data as $val) { - $this->add($val); - } - } elseif (is_object($data)) { - $this->_data[] = $data; - } elseif (!is_null($data)) { - $this->_data[] = new Horde_Imap_Client_Data_Format_Atom($data); - } - - return $this; - } - - /** - */ - public function __toString() - { - $out = ''; - - foreach ($this as $val) { - if ($val instanceof $this) { - $out .= '(' . $val->escape() . ') '; - } elseif (($val instanceof Horde_Imap_Client_Data_Format_String) && - $val->literal()) { - /* ERROR: Requires literal output. */ - return ''; - } else { - $out .= $val->escape() . ' '; - } - } - - return rtrim($out); - } - - /* Countable methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function count() - { - return count($this->_data); - } - - /* IteratorAggregate method. */ - - /** - * Iterator loops through the data elements contained in this list. - */ - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_data); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/ListMailbox.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/ListMailbox.php deleted file mode 100644 index cd64b417d34..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/ListMailbox.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_ListMailbox -extends Horde_Imap_Client_Data_Format_Mailbox -{ - /** - */ - protected function _filterParams() - { - $ob = parent::_filterParams(); - - /* Don't quote % or * characters. */ - $ob->no_quote_list = true; - - return $ob; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/ListMailbox/Utf8.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/ListMailbox/Utf8.php deleted file mode 100644 index f46043445f3..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/ListMailbox/Utf8.php +++ /dev/null @@ -1,39 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_ListMailbox_Utf8 -extends Horde_Imap_Client_Data_Format_Mailbox_Utf8 -{ - /** - */ - protected function _filterParams() - { - $ob = parent::_filterParams(); - - /* Don't quote % or * characters. */ - $ob->no_quote_list = true; - - return $ob; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Mailbox.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Mailbox.php deleted file mode 100644 index c7476af9603..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Mailbox.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Mailbox -extends Horde_Imap_Client_Data_Format_Astring -{ - /** - * Mailbox encoding. - * - * @var string - */ - protected $_encoding = 'utf7imap'; - - /** - * Mailbox object. - * - * @var Horde_Imap_Client_Mailbox - */ - protected $_mailbox; - - /** - * @param mixed $data Either a mailbox object or a UTF-8 mailbox name. - */ - public function __construct($data) - { - $this->_mailbox = Horde_Imap_Client_Mailbox::get($data); - - parent::__construct($this->_mailbox->{$this->_encoding}); - } - - /** - */ - public function __toString() - { - return strval($this->_mailbox); - } - - /** - */ - public function getData() - { - return $this->_mailbox; - } - - /** - * @throws Horde_Imap_Client_Exception - */ - public function binary() - { - if (parent::binary()) { - // Mailbox data can NEVER be sent as binary. - /* @todo: Disable until Horde_Imap_Client 3.0 */ - // throw new Horde_Imap_Client_Exception( - // 'Client error: can not send mailbox to IMAP server as binary data.' - // ); - - // Temporary fix: send a blank mailbox string. - $this->_mailbox = Horde_Imap_Client_Mailbox::get(''); - } - - return false; - } - - /** - */ - public function length() - { - return strlen($this->_mailbox->{$this->_encoding}); - } - - /** - */ - public function getStream() - { - $stream = new Horde_Stream_Temp(); - $stream->add($this->_mailbox->{$this->_encoding}); - return $stream; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Mailbox/Utf8.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Mailbox/Utf8.php deleted file mode 100644 index 7950476a92f..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Mailbox/Utf8.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Mailbox_Utf8 -extends Horde_Imap_Client_Data_Format_Mailbox -implements Horde_Imap_Client_Data_Format_String_Support_Nonascii -{ - /** - */ - protected $_encoding = 'utf8'; - - /** - */ - public function __construct($data) - { - parent::__construct($data); - - /* RFC 3501 allows any US-ASCII character, except null (\0), in - * mailbox data. - * RFC 6855 [3] institutes additional limitations on valid mailbox - * characters, to comply with RFC 5198 [2] (Net-Unicode Definition): - * "MUST NOT contain control characters (U+0000-U+001F and - * U+0080-U+009F), a delete character (U+007F), a line separator - * (U+2028), or a paragraph separator (U+2029)." */ - if ($this->quoted() && - preg_match('/[\x00-\x1f\x7f\x80-\x9f\x{2028}\x{2029}]/u', strval($this))) { - throw new Horde_Imap_Client_Data_Format_Exception( - 'Invalid character found in mailbox data.' - ); - } - - if ($this->literal()) { - $this->forceQuoted(); - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Nil.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Nil.php deleted file mode 100644 index cd95b46e5e9..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Nil.php +++ /dev/null @@ -1,46 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Nil extends Horde_Imap_Client_Data_Format -{ - /** - */ - public function __construct($data = null) - { - // Don't store any data in object. - } - - /** - */ - public function __toString() - { - return ''; - } - - /** - */ - public function escape() - { - return 'NIL'; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Nstring.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Nstring.php deleted file mode 100644 index 0a34da58712..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Nstring.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Nstring extends Horde_Imap_Client_Data_Format_String -{ - /** - */ - public function __construct($data = null) - { - /* Data can be null (NIL) here. */ - if (is_null($data)) { - $this->_data = null; - } else { - parent::__construct($data); - } - } - - /** - */ - public function __toString() - { - return is_null($this->_data) - ? '' - : parent::__toString(); - } - - /** - */ - public function escape() - { - return is_null($this->_data) - ? 'NIL' - : parent::escape(); - } - - public function escapeStream() - { - if (is_null($this->_data)) { - $stream = new Horde_Stream_Temp(); - $stream->add('NIL', true); - return $stream->stream; - } - - return parent::escapeStream(); - } - - /** - */ - public function quoted() - { - return is_null($this->_data) - ? false - : parent::quoted(); - } - - /** - */ - public function length() - { - return is_null($this->_data) - ? 0 - : parent::length(); - } - - /** - */ - public function getStream() - { - return is_null($this->_data) - ? new Horde_Stream_Temp() - : parent::getStream(); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Nstring/Nonascii.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Nstring/Nonascii.php deleted file mode 100644 index 4aa72e434c8..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Nstring/Nonascii.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.25.0 - */ -class Horde_Imap_Client_Data_Format_Nstring_Nonascii -extends Horde_Imap_Client_Data_Format_Nstring -implements Horde_Imap_Client_Data_Format_String_Support_Nonascii -{ -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/Number.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/Number.php deleted file mode 100644 index 43a2da4bf31..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/Number.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_Number extends Horde_Imap_Client_Data_Format -{ - /** - */ - public function __toString() - { - return strval(intval($this->_data)); - } - - /** - */ - public function verify() - { - if (!is_numeric($this->_data)) { - throw new Horde_Imap_Client_Data_Format_Exception('Illegal character in IMAP number.'); - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/String.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/String.php deleted file mode 100644 index cca905797da..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/String.php +++ /dev/null @@ -1,219 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Format_String -extends Horde_Imap_Client_Data_Format -{ - /** - * String filter parameters. - * - * @var string - */ - protected $_filter; - - /** - * @param array $opts Additional options: - * - eol: (boolean) If true, normalize EOLs in input. @since 2.2.0 - * - skipscan: (boolean) If true, don't scan input for - * binary/literal/quoted data. @since 2.2.0 - * - * @throws Horde_Imap_Client_Data_Format_Exception - */ - public function __construct($data, array $opts = array()) - { - /* String data is stored in a stream. */ - $this->_data = new Horde_Stream_Temp(); - - if (empty($opts['skipscan'])) { - $this->_filter = $this->_filterParams(); - stream_filter_register('horde_imap_client_string', 'Horde_Imap_Client_Data_Format_Filter_String'); - $res = stream_filter_append($this->_data->stream, 'horde_imap_client_string', STREAM_FILTER_WRITE, $this->_filter); - } else { - $res = null; - } - - if (empty($opts['eol'])) { - $res2 = null; - } else { - stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol'); - $res2 = stream_filter_append($this->_data->stream, 'horde_eol', STREAM_FILTER_WRITE); - } - - $this->_data->add($data); - - if (!is_null($res)) { - stream_filter_remove($res); - } - if (!is_null($res2)) { - stream_filter_remove($res2); - } - - if (isset($this->_filter) && - $this->_filter->nonascii && - !($this instanceof Horde_Imap_Client_Data_Format_String_Support_Nonascii)) { - throw new Horde_Imap_Client_Data_Format_Exception( - 'String contains non-ASCII characters.' - ); - } - } - - /** - * Return the base string filter parameters. - * - * @return object Filter parameters. - */ - protected function _filterParams() - { - return new stdClass; - } - - /** - */ - public function __toString() - { - return $this->_data->getString(0); - } - - /** - */ - public function escape() - { - if ($this->literal()) { - throw new Horde_Imap_Client_Data_Format_Exception('String requires literal to output.'); - } - - return $this->quoted() - ? stream_get_contents($this->escapeStream()) - : $this->_data->getString(0); - } - - /** - * Return the escaped string as a stream. - * - * @return resource The IMAP escaped stream. - */ - public function escapeStream() - { - if ($this->literal()) { - throw new Horde_Imap_Client_Data_Format_Exception('String requires literal to output.'); - } - - rewind($this->_data->stream); - - $stream = new Horde_Stream_Temp(); - $stream->add($this->_data, true); - - stream_filter_register('horde_imap_client_string_quote', 'Horde_Imap_Client_Data_Format_Filter_Quote'); - stream_filter_append($stream->stream, 'horde_imap_client_string_quote', STREAM_FILTER_READ); - - return $stream->stream; - } - - /** - * Does this data item require quoted string output? - * - * @return boolean True if quoted output is required. - */ - public function quoted() - { - /* IMAP strings MUST be quoted if they are not a literal. */ - return (!isset($this->_filter) || !$this->_filter->literal); - } - - /** - * Force item to be output quoted. - */ - public function forceQuoted() - { - $this->_filter = $this->_filterParams(); - $this->_filter->binary = false; - $this->_filter->literal = false; - $this->_filter->quoted = true; - } - - /** - * Does this data item require literal string output? - * - * @return boolean True if literal output is required. - */ - public function literal() - { - return (isset($this->_filter) && $this->_filter->literal); - } - - /** - * Force item to be output as a literal. - */ - public function forceLiteral() - { - $this->_filter = $this->_filterParams(); - // Keep binary status, if set - $this->_filter->literal = true; - $this->_filter->quoted = false; - } - - /** - * If literal output, is the data binary? - * - * @return boolean True if the literal output is binary. - */ - public function binary() - { - return (isset($this->_filter) && !empty($this->_filter->binary)); - } - - /** - * Force item to be output as a binary literal. - */ - public function forceBinary() - { - $this->_filter = $this->_filterParams(); - $this->_filter->binary = true; - $this->_filter->literal = true; - $this->_filter->quoted = false; - } - - /** - * Return the length of the data. - * - * @since 2.2.0 - * - * @return integer Data length. - */ - public function length() - { - return $this->_data->length(); - } - - /** - * Return the contents of the string as a stream object. - * - * @since 2.3.0 - * - * @return Horde_Stream The stream object. - */ - public function getStream() - { - return $this->_data; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/String/Nonascii.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/String/Nonascii.php deleted file mode 100644 index 979d8cceb70..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/String/Nonascii.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.25.0 - */ -class Horde_Imap_Client_Data_Format_String_Nonascii -extends Horde_Imap_Client_Data_Format_String -implements Horde_Imap_Client_Data_Format_String_Support_Nonascii -{ -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Format/String/Support/Nonascii.php b/lib/horde/framework/Horde/Imap/Client/Data/Format/String/Support/Nonascii.php deleted file mode 100644 index 0a5d81122cc..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Format/String/Support/Nonascii.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.25.0 - */ -interface Horde_Imap_Client_Data_Format_String_Support_Nonascii -{ -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Namespace.php b/lib/horde/framework/Horde/Imap/Client/Data/Namespace.php deleted file mode 100644 index 61e3f35f9d5..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Namespace.php +++ /dev/null @@ -1,160 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.21.0 - * - * @property-read string $base The namespace base ($name without trailing - * delimiter) (UTF-8). - * @property string $delimiter The namespace delimiter. - * @property boolean $hidden Is this a hidden namespace? - * @property string $name The namespace name (UTF-8). - * @property string $translation Returns the translated name of the namespace - * (UTF-8). - * @property integer $type The namespace type. Either self::NS_PERSONAL, - * self::NS_OTHER, or self::NS_SHARED. - */ -class Horde_Imap_Client_Data_Namespace implements Serializable -{ - /* Namespace type constants. */ - const NS_PERSONAL = 1; - const NS_OTHER = 2; - const NS_SHARED = 3; - - /** - * Data object. - * - * @var array - */ - protected $_data = array(); - - /** - * Strips namespace information from the given mailbox name. - * - * @param string $mbox Mailbox name. - * - * @return string Mailbox name with namespace prefix stripped. - */ - public function stripNamespace($mbox) - { - $mbox = strval($mbox); - $name = $this->name; - - return (strlen($name) && (strpos($mbox, $name) === 0)) - ? substr($mbox, strlen($name)) - : $mbox; - } - - /** - */ - public function __get($name) - { - if (isset($this->_data[$name])) { - return $this->_data[$name]; - } - - switch ($name) { - case 'base': - return rtrim($this->name, $this->delimiter); - - case 'delimiter': - case 'name': - case 'translation': - return ''; - - case 'hidden': - return false; - - case 'type': - return self::NS_PERSONAL; - } - - return null; - } - - /** - */ - public function __set($name, $value) - { - switch ($name) { - case 'delimiter': - case 'name': - case 'translation': - $this->_data[$name] = strval($value); - break; - - case 'hidden': - $this->_data[$name] = (bool)$value; - break; - - case 'type': - $this->_data[$name] = intval($value); - break; - } - } - - /** - */ - public function __isset($name) - { - return isset($this->_data[$name]); - } - - /** - */ - public function __toString() - { - return $this->name; - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version change.'); - } - $this->__unserialize($data); - } - - /** - * @return array - */ - public function __serialize() - { - return $this->_data; - } - - public function __unserialize(array $data) - { - $this->_data = $data; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/SearchCharset.php b/lib/horde/framework/Horde/Imap/Client/Data/SearchCharset.php deleted file mode 100644 index 181c285f995..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/SearchCharset.php +++ /dev/null @@ -1,198 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.24.0 - * - * @property-read array $charsets The list of valid charsets that have been - * discovered on the server. - */ -class Horde_Imap_Client_Data_SearchCharset -implements Serializable, SplSubject -{ - /** - * Base client object. - * - * @var Horde_Imap_Client_Base - */ - protected $_baseob; - - /** - * Charset data. - * - * @var array - */ - protected $_charsets = array( - 'US-ASCII' => true - ); - - /** - * Observers. - * - * @var array - */ - protected $_observers = array(); - - /** - */ - public function __get($name) - { - switch ($name) { - case 'charsets': - return array_keys(array_filter($this->_charsets)); - } - } - - /** - */ - public function setBaseOb(Horde_Imap_Client_Base $ob) - { - $this->_baseob = $ob; - } - - /** - * Query the validity of a charset. - * - * @param string $charset The charset to query. - * @param boolean $cached If true, only query cached values. - * - * @return boolean True if the charset is valid for searching. - */ - public function query($charset, $cached = false) - { - $charset = Horde_String::upper($charset); - - if (isset($this->_charsets[$charset])) { - return $this->_charsets[$charset]; - } elseif ($cached) { - return null; - } - - if (!$this->_baseob) { - throw new RuntimeException( - 'Base object needs to be defined to query for charset.' - ); - } - - /* Use a dummy search query and search for BADCHARSET response. */ - $query = new Horde_Imap_Client_Search_Query(); - $query->charset($charset, false); - $query->ids($this->_baseob->getIdsOb(1, true)); - $query->text('a'); - try { - $this->_baseob->search('INBOX', $query, array( - 'nocache' => true, - 'sequence' => true - )); - $this->_charsets[$charset] = true; - } catch (Horde_Imap_Client_Exception $e) { - $this->_charsets[$charset] = ($e->getCode() !== Horde_Imap_Client_Exception::BADCHARSET); - } - - $this->notify(); - - return $this->_charsets[$charset]; - } - - /** - * Set the validity of a given charset. - * - * @param string $charset The charset. - * @param boolean $valid Is charset valid? - */ - public function setValid($charset, $valid = true) - { - $charset = Horde_String::upper($charset); - $valid = (bool)$valid; - - if (!isset($this->_charsets[$charset]) || - ($this->_charsets[$charset] !== $valid)) { - $this->_charsets[$charset] = $valid; - $this->notify(); - } - } - - /* SplSubject methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function attach(SplObserver $observer) - { - $this->detach($observer); - $this->_observers[] = $observer; - } - - /** - */ - #[ReturnTypeWillChange] - public function detach(SplObserver $observer) - { - if (($key = array_search($observer, $this->_observers, true)) !== false) { - unset($this->_observers[$key]); - } - } - - /** - * Notification is triggered internally whenever the object's internal - * data storage is altered. - */ - #[ReturnTypeWillChange] - public function notify() - { - foreach ($this->_observers as $val) { - $val->update($this); - } - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version change'); - } - $this->__unserialize($data); - } - - /** - * @return array - */ - public function __serialize() - { - return $this->_charsets; - } - - public function __unserialize(array $data) - { - $this->_charsets = $data; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/SearchCharset/Utf8.php b/lib/horde/framework/Horde/Imap/Client/Data/SearchCharset/Utf8.php deleted file mode 100644 index a842020d72d..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/SearchCharset/Utf8.php +++ /dev/null @@ -1,78 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.24.0 - */ -class Horde_Imap_Client_Data_SearchCharset_Utf8 -extends Horde_Imap_Client_Data_SearchCharset -{ - /** - * Charset data. - * - * @var array - */ - protected $_charsets = array( - 'US-ASCII' => true, - 'UTF-8' => true - ); - - /** - */ - public function query($charset, $cached = false) - { - return isset($this->_charsets[Horde_String::upper($charset)]); - } - - /** - */ - public function setValid($charset, $valid = true) - { - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return ''; - } - - /** - */ - public function unserialize($data) - { - } - - /** - * @return array - */ - public function __serialize() - { - return array(); - } - - public function __unserialize(array $data) - { - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Sync.php b/lib/horde/framework/Horde/Imap/Client/Data/Sync.php deleted file mode 100644 index b0fa0804767..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Sync.php +++ /dev/null @@ -1,267 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.2.0 - * - * @property-read Horde_Imap_Client_Ids $flagsuids List of messages with flag - * changes. - * @property-read Horde_Imap_Client_Ids $newmsgsuids List of new messages. - * @property-read Horde_Imap_Client_Ids $vanisheduids List of messages that - * have vanished. - */ -class Horde_Imap_Client_Data_Sync -{ - /** - * Mappings of status() values to sync keys. - * - * @since 2.8.0 - * - * @var array - */ - public static $map = array( - 'H' => 'highestmodseq', - 'M' => 'messages', - 'U' => 'uidnext', - 'V' => 'uidvalidity' - ); - - /** - * Are there messages that have had flag changes? - * - * @var boolean - */ - public $flags = null; - - /** - * The previous value of HIGHESTMODSEQ. - * - * @since 2.8.0 - * - * @var integer - */ - public $highestmodseq = null; - - /** - * The synchronized mailbox. - * - * @var Horde_Imap_Client_Mailbox - */ - public $mailbox; - - /** - * The previous number of messages in the mailbox. - * - * @since 2.8.0 - * - * @var integer - */ - public $messages = null; - - /** - * Are there new messages? - * - * @var boolean - */ - public $newmsgs = null; - - /** - * The previous value of UIDNEXT. - * - * @since 2.8.0 - * - * @var integer - */ - public $uidnext = null; - - /** - * The previous value of UIDVALIDITY. - * - * @since 2.8.0 - * - * @var integer - */ - public $uidvalidity = null; - - /** - * The UIDs of messages that are guaranteed to have vanished. This list is - * only guaranteed to be available if the server supports QRESYNC or a - * list of known UIDs is passed to the sync() method. - * - * @var Horde_Imap_Client_Ids - */ - public $vanished = null; - - /** - * UIDs of messages that have had flag changes. - * - * @var Horde_Imap_Client_Ids - */ - protected $_flagsuids; - - /** - * UIDs of new messages. - * - * @var Horde_Imap_Client_Ids - */ - protected $_newmsgsuids; - - /** - * UIDs of messages that have vanished. - * - * @var Horde_Imap_Client_Ids - */ - protected $_vanisheduids; - - /** - * Constructor. - * - * @param Horde_Imap_Client_Base $base_ob Base driver object. - * @param mixed $mailbox Mailbox to sync. - * @param array $sync Token sync data. - * @param array $curr Current sync data. - * @param integer $criteria Mask of criteria to return. - * @param Horde_Imap_Client_Ids $ids List of known UIDs. - * - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_Sync - */ - public function __construct(Horde_Imap_Client_Base $base_ob, $mailbox, - $sync, $curr, $criteria, $ids) - { - foreach (self::$map as $key => $val) { - if (isset($sync[$key])) { - $this->$val = $sync[$key]; - } - } - - /* Check uidvalidity. */ - if (!$this->uidvalidity || ($curr['V'] != $this->uidvalidity)) { - throw new Horde_Imap_Client_Exception_Sync('UIDs in cached mailbox have changed.', Horde_Imap_Client_Exception_Sync::UIDVALIDITY_CHANGED); - } - - $this->mailbox = $mailbox; - - /* This was a UIDVALIDITY check only. */ - if (!$criteria) { - return; - } - - $sync_all = ($criteria & Horde_Imap_Client::SYNC_ALL); - - /* New messages. */ - if ($sync_all || - ($criteria & Horde_Imap_Client::SYNC_NEWMSGS) || - ($criteria & Horde_Imap_Client::SYNC_NEWMSGSUIDS)) { - $this->newmsgs = empty($this->uidnext) - ? !empty($curr['U']) - : (!empty($curr['U']) && ($curr['U'] > $this->uidnext)); - - if ($this->newmsgs && - ($sync_all || - ($criteria & Horde_Imap_Client::SYNC_NEWMSGSUIDS))) { - $new_ids = empty($this->uidnext) - ? Horde_Imap_Client_Ids::ALL - : ($this->uidnext . ':' . $curr['U']); - - $squery = new Horde_Imap_Client_Search_Query(); - $squery->ids(new Horde_Imap_Client_Ids($new_ids)); - $sres = $base_ob->search($mailbox, $squery); - - $this->_newmsgsuids = $sres['match']; - } - } - - /* Do single status call to get all necessary data. */ - if ($this->highestmodseq && - ($sync_all || - ($criteria & Horde_Imap_Client::SYNC_FLAGS) || - ($criteria & Horde_Imap_Client::SYNC_FLAGSUIDS) || - ($criteria & Horde_Imap_Client::SYNC_VANISHED) || - ($criteria & Horde_Imap_Client::SYNC_VANISHEDUIDS))) { - $status_sync = $base_ob->status($mailbox, Horde_Imap_Client::STATUS_SYNCMODSEQ | Horde_Imap_Client::STATUS_SYNCFLAGUIDS | Horde_Imap_Client::STATUS_SYNCVANISHED); - - if (!is_null($ids)) { - $ids = $base_ob->resolveIds($mailbox, $ids); - } - } - - /* Flag changes. */ - if ($sync_all || ($criteria & Horde_Imap_Client::SYNC_FLAGS)) { - $this->flags = $this->highestmodseq - ? ($this->highestmodseq != $curr['H']) - : true; - } - - if ($sync_all || ($criteria & Horde_Imap_Client::SYNC_FLAGSUIDS)) { - if ($this->highestmodseq) { - if ($this->highestmodseq == $status_sync['syncmodseq']) { - $this->_flagsuids = is_null($ids) - ? $status_sync['syncflaguids'] - : $base_ob->getIdsOb(array_intersect($ids->ids, $status_sync['syncflaguids']->ids)); - } else { - $squery = new Horde_Imap_Client_Search_Query(); - $squery->modseq($this->highestmodseq + 1); - $sres = $base_ob->search($mailbox, $squery, array( - 'ids' => $ids - )); - $this->_flagsuids = $sres['match']; - } - } else { - /* Without MODSEQ, need to mark all FLAGS as changed. */ - $this->_flagsuids = $base_ob->resolveIds($mailbox, is_null($ids) ? $base_ob->getIdsOb(Horde_Imap_Client_Ids::ALL) : $ids); - } - } - - /* Vanished messages. */ - if ($sync_all || - ($criteria & Horde_Imap_Client::SYNC_VANISHED) || - ($criteria & Horde_Imap_Client::SYNC_VANISHEDUIDS)) { - if ($this->highestmodseq && - ($this->highestmodseq == $status_sync['syncmodseq'])) { - $vanished = is_null($ids) - ? $status_sync['syncvanished'] - : $base_ob->getIdsOb(array_intersect($ids->ids, $status_sync['syncvanished']->ids)); - } else { - $vanished = $base_ob->vanished($mailbox, $this->highestmodseq ? $this->highestmodseq : 1, array( - 'ids' => $ids - )); - } - - $this->vanished = (bool)count($vanished); - $this->_vanisheduids = $vanished; - } - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'flagsuids': - case 'newmsgsuids': - case 'vanisheduids': - return empty($this->{'_' . $name}) - ? new Horde_Imap_Client_Ids() - : $this->{'_' . $name}; - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Data/Thread.php b/lib/horde/framework/Horde/Imap/Client/Data/Thread.php deleted file mode 100644 index 391dab7efc5..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Data/Thread.php +++ /dev/null @@ -1,231 +0,0 @@ - - * @category Horde - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Data_Thread implements Countable, Serializable -{ - /** - * Internal thread data structure. Keys are base values, values are arrays - * with keys as the ID and values as the level. - * - * @var array - */ - protected $_thread = array(); - - /** - * The index type. - * - * @var string - */ - protected $_type; - - /** - * Constructor. - * - * @param array $data See $_thread. - * @param string $type Either 'sequence' or 'uid'. - */ - public function __construct($data, $type) - { - $this->_thread = $data; - $this->_type = $type; - } - - /** - * Return the ID type. - * - * @return string Either 'sequence' or 'uid'. - */ - public function getType() - { - return $this->_type; - } - - /** - * Return the sorted list of messages indices. - * - * @return Horde_Imap_Client_Ids The sorted list of messages. - */ - public function messageList() - { - return new Horde_Imap_Client_Ids($this->_getAllIndices(), $this->getType() == 'sequence'); - } - - /** - * Returns the list of messages in a thread. - * - * @param integer $index An index contained in the thread. - * - * @return array Keys are indices, values are objects with the following - * properties: - * - base: (integer) Base ID of the thread. If null, thread is a single - * message. - * - last: (boolean) If true, this is the last index in the sublevel. - * - level: (integer) The sublevel of the index. - */ - public function getThread($index) - { - foreach ($this->_thread as $v) { - if (isset($v[$index])) { - reset($v); - - $ob = new stdClass; - $ob->base = (count($v) > 1) ? key($v) : null; - $ob->last = false; - - $levels = $out = array(); - $last = 0; - - while (($v2 = current($v)) !== false) { - $k2 = key($v); - $ob2 = clone $ob; - $ob2->level = $v2; - $out[$k2] = $ob2; - - if (($last < $v2) && isset($levels[$v2])) { - $out[$levels[$v2]]->last = true; - } - $levels[$v2] = $k2; - $last = $v2; - next($v); - } - - foreach ($levels as $v) { - $out[$v]->last = true; - } - - return $out; - } - } - - return array(); - } - - /** - * Returns array of all threads. - * - * @return array Keys of thread arrays are indices, values are objects with the following - * properties: - * - base: (integer) Base ID of the thread. If null, thread is a single - * message. - * - last: (boolean) If true, this is the last index in the sublevel. - * - level: (integer) The sublevel of the index. - */ - public function getThreads() - { - $data = array(); - foreach ($this->_thread as $v) { - reset($v); - - $ob = new stdClass; - $ob->base = (count($v) > 1) ? key($v) : null; - $ob->last = false; - - $levels = $out = array(); - $last = 0; - - while (($v2 = current($v)) !== false) { - $k2 = key($v); - $ob2 = clone $ob; - $ob2->level = $v2; - $out[$k2] = $ob2; - - if (($last < $v2) && isset($levels[$v2])) { - $out[$levels[$v2]]->last = true; - } - $levels[$v2] = $k2; - $last = $v2; - next($v); - } - - foreach ($levels as $v) { - $out[$v]->last = true; - } - - $data[] = $out; - } - - return $data; - } - - /* Countable methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function count() - { - return count($this->_getAllIndices()); - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version changed.'); - } - $this->__unserialize($data); - } - - /** - * @return array - */ - public function __serialize() - { - return [$this->_thread, $this->_type]; - } - - public function __unserialize(array $data) - { - list($this->_thread, $this->_type) = $data; - } - - /* Protected methods. */ - - /** - * Return all indices. - * - * @return array An array of indices. - */ - protected function _getAllIndices() - { - $out = array(); - - foreach ($this->_thread as $val) { - $out += $val; - } - - return array_keys($out); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/DateTime.php b/lib/horde/framework/Horde/Imap/Client/DateTime.php deleted file mode 100644 index f7225b7cdf9..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/DateTime.php +++ /dev/null @@ -1,119 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_DateTime extends DateTime -{ - /** - */ - public function __construct($time = null, $tz = null) - { - /* See https://bugs.php.net/bug.php?id=67118 */ - $bug_67118 = (version_compare(PHP_VERSION, '5.6', '>=')) || - in_array(PHP_VERSION, array('5.4.29', '5.5.13')); - $tz = new DateTimeZone('UTC'); - - /* Bug #14381 Catch malformed offset - which doesn't cause - DateTime to throw exception. */ - if ($time !== null && substr(rtrim($time), -5) === ' 0000') { - $time = substr(trim($time), 0, strlen(trim($time)) - 5) . ' +0000'; - try { - if ($bug_67118) { - new DateTime($time, $tz); - } - parent::__construct($time, $tz); - return; - } catch (Exception $e) {} - } - - try { - if ($bug_67118) { - new DateTime($time === null ? 'now' : $time, $tz); - } - parent::__construct($time === null ? 'now' : $time, $tz); - return; - } catch (Exception $e) {} - - /* Check for malformed day-of-week parts, usually incorrectly - * localized. E.g. Fr, 15 Apr 2016 15:15:09 +0000 */ - if ($time !== null && !preg_match("/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun),/", $time)) { - $time = preg_replace("/^(\S*,)/", '', $time, 1, $i); - if ($i) { - try { - if ($bug_67118) { - new DateTime($time, $tz); - } - parent::__construct($time, $tz); - return; - } catch (Exception $e) {} - } - } - - /* Bug #5717 - Check for UT vs. UTC. */ - if ($time !== null && substr(rtrim($time), -3) === ' UT') { - try { - if ($bug_67118) { - new DateTime($time . 'C', $tz); - } - parent::__construct($time . 'C', $tz); - return; - } catch (Exception $e) {} - } - - /* Bug #9847 - Catch paranthesized timezone information at end of date - * string. */ - $date = preg_replace("/\s*\([^\)]+\)\s*$/", '', $time, -1, $i); - if ($i) { - try { - if ($bug_67118) { - new DateTime($date, $tz); - } - parent::__construct($date, $tz); - return; - } catch (Exception $e) {} - } - - parent::__construct('@-1', $tz); - } - - /** - * String representation: UNIX timestamp. - */ - public function __toString() - { - return $this->error() - ? '0' - : strval($this->getTimestamp()); - } - - /** - * Was this an unparseable date? - * - * @return boolean True if unparseable. - */ - public function error() - { - return ($this->getTimestamp() === -1); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Exception.php b/lib/horde/framework/Horde/Imap/Client/Exception.php deleted file mode 100644 index dce0d144884..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Exception.php +++ /dev/null @@ -1,303 +0,0 @@ - - * @category Horde - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Exception extends Horde_Exception_Wrapped -{ - /* Error message codes. */ - - /** - * Unspecified error (DEFAULT). - */ - const UNSPECIFIED = 0; - - /** - * There was an unrecoverable error in UTF7IMAP -> UTF8 conversion. - */ - const UTF7IMAP_CONVERSION = 3; - - /** - * The server ended the connection. - */ - const DISCONNECT = 4; - - /** - * The charset used in the search query is not supported on the - * server. */ - const BADCHARSET = 5; - - /** - * There were errors parsing the MIME/RFC 2822 header of the part. - */ - const PARSEERROR = 6; - - /** - * The server could not decode the MIME part (see RFC 3516). - */ - const UNKNOWNCTE = 7; - - /** - * The comparator specified by setComparator() was not recognized by the - * IMAP server - */ - const BADCOMPARATOR = 9; - - /** - * RFC 7162 [3.1.2.2] - All mailboxes are not required to support - * mod-sequences. - */ - const MBOXNOMODSEQ = 10; - - /** - * Thrown if server denies the network connection. - */ - const SERVER_CONNECT = 11; - - /** - * Thrown if read error for server response. - */ - const SERVER_READERROR = 12; - - /** - * Thrown if write error in server interaction. - */ - const SERVER_WRITEERROR = 16; - - /** - * Thrown on CATENATE if the URL is invalid. - */ - const CATENATE_BADURL = 13; - - /** - * Thrown on CATENATE if the message was too big. - */ - const CATENATE_TOOBIG = 14; - - /** - * Thrown on CREATE if special-use attribute is not supported. - */ - const USEATTR = 15; - - /** - * The user did not have permissions to carry out the operation. - */ - const NOPERM = 17; - - /** - * The operation was not successful because another user is holding - * a necessary resource. The operation may succeed if attempted later. - */ - const INUSE = 18; - - /** - * The operation failed because data on the server was corrupt. - */ - const CORRUPTION = 19; - - /** - * The operation failed because it exceeded some limit on the server. - */ - const LIMIT = 20; - - /** - * The operation failed because the user is over their quota. - */ - const OVERQUOTA = 21; - - /** - * The operation failed because the requested creation object already - * exists. - */ - const ALREADYEXISTS = 22; - - /** - * The operation failed because the requested deletion object did not - * exist. - */ - const NONEXISTENT = 23; - - /** - * Setting metadata failed because the size of its value is too large. - * The maximum octet count the server is willing to accept will be - * in the exception message string. - */ - const METADATA_MAXSIZE = 24; - - /** - * Setting metadata failed because the maximum number of allowed - * annotations has already been reached. - */ - const METADATA_TOOMANY = 25; - - /** - * Setting metadata failed because the server does not support private - * annotations on one of the specified mailboxes. - */ - const METADATA_NOPRIVATE = 26; - - /** - * Invalid metadata entry. - */ - const METADATA_INVALID = 27; - - - // Login failures - - /** - * Could not start mandatory TLS connection. - */ - const LOGIN_TLSFAILURE = 100; - - /** - * Could not find an available authentication method. - */ - const LOGIN_NOAUTHMETHOD = 101; - - /** - * Generic authentication failure. - */ - const LOGIN_AUTHENTICATIONFAILED = 102; - - /** - * Remote server is unavailable. - */ - const LOGIN_UNAVAILABLE = 103; - - /** - * Authentication succeeded, but authorization failed. - */ - const LOGIN_AUTHORIZATIONFAILED = 104; - - /** - * Authentication is no longer permitted with this passphrase. - */ - const LOGIN_EXPIRED = 105; - - /** - * Login requires privacy. - */ - const LOGIN_PRIVACYREQUIRED = 106; - - /** - * Server verification failed (SCRAM authentication). - */ - const LOGIN_SERVER_VERIFICATION_FAILED = 107; - - - // Mailbox access failures - - /** - * Could not open/access mailbox - */ - const MAILBOX_NOOPEN = 200; - - /** - * Could not complete the command because the mailbox is read-only - */ - const MAILBOX_READONLY = 201; - - - // POP3 specific error codes - - /** - * Temporary issue. Generally, there is no need to alarm the user for - * errors of this type. - */ - const POP3_TEMP_ERROR = 300; - - /** - * Permanent error indicated by server. - */ - const POP3_PERM_ERROR = 301; - - - // Unsupported feature error codes - - /** - * Function/feature is not supported on this server. - */ - const NOT_SUPPORTED = 400; - - - /** - * Raw error message (in English). - * - * @since 2.18.0 - * - * @var string - */ - public $raw_msg = ''; - - /** - * Constructor. - * - * @param string $message Error message (non-translated). - * @param int $code Error code. - */ - public function __construct($message = null, $code = null) - { - parent::__construct($message, $code); - - $this->raw_msg = $this->message; - try { - $this->message = Horde_Imap_Client_Translation::t($this->message); - } catch (Horde_Translation_Exception $e) {} - } - - /** - * Allow the error message to be altered. - * - * @param string $msg Error message. - */ - public function setMessage($msg) - { - $this->message = strval($msg); - } - - /** - * Allow the error code to be altered. - * - * @param integer $code Error code. - */ - public function setCode($code) - { - $this->code = intval($code); - } - - /** - * Perform substitution of variables in the error message. - * - * Needed to allow for correct translation of error message. - * - * @since 2.22.0 - * - * @param array $args Arguments used for substitution. - */ - public function messagePrintf(array $args = array()) - { - $this->raw_msg = vsprintf($this->raw_msg, $args); - $this->message = vsprintf($this->message, $args); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Exception/NoSupportExtension.php b/lib/horde/framework/Horde/Imap/Client/Exception/NoSupportExtension.php deleted file mode 100644 index 83a1050fca1..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Exception/NoSupportExtension.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Exception_NoSupportExtension -extends Horde_Imap_Client_Exception -{ - /** - * The extension not supported on the server. - * - * @var string - */ - public $extension; - - /** - * Constructor. - * - * @param string $extension The extension not supported on the server. - * @param string $msg A non-standard error message to use instead - * of the default. - */ - public function __construct($extension, $msg = null) - { - $this->extension = $extension; - - if (is_null($msg)) { - $msg = sprintf( - Horde_Imap_Client_Translation::r("The server does not support the %s extension."), - $extension - ); - } - - parent::__construct($msg, self::NOT_SUPPORTED); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Exception/NoSupportPop3.php b/lib/horde/framework/Horde/Imap/Client/Exception/NoSupportPop3.php deleted file mode 100644 index c1782950962..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Exception/NoSupportPop3.php +++ /dev/null @@ -1,40 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Exception_NoSupportPop3 -extends Horde_Imap_Client_Exception -{ - /** - * Constructor. - * - * @param string $feature The feature not supported in POP3. - */ - public function __construct($feature) - { - parent::__construct( - Horde_Imap_Client_Translation::r("%s not supported on POP3 servers."), - self::NOT_SUPPORTED - ); - $this->messagePrintf(array($feature)); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Exception/SearchCharset.php b/lib/horde/framework/Horde/Imap/Client/Exception/SearchCharset.php deleted file mode 100644 index 07964335836..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Exception/SearchCharset.php +++ /dev/null @@ -1,50 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Exception_SearchCharset -extends Horde_Imap_Client_Exception -{ - /** - * Charset that was attempted to be converted to. - * - * @var string - */ - public $charset; - - /** - * Constructor. - * - * @param string $charset The charset that was attempted to be converted - * to. - */ - public function __construct($charset) - { - $this->charset = $charset; - - parent::__construct( - Horde_Imap_Client_Translation::r("Cannot convert search query text to new charset"), - self::BADCHARSET - ); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Exception/ServerResponse.php b/lib/horde/framework/Horde/Imap/Client/Exception/ServerResponse.php deleted file mode 100644 index 6c83276b22b..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Exception/ServerResponse.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * - * @property-read string $command The command that caused the BAD/NO error - * status. - * @property-read array $resp_data The response data array. - * @property-read integer $status Server error status. - */ -class Horde_Imap_Client_Exception_ServerResponse extends Horde_Imap_Client_Exception -{ - /** - * Pipeline object. - * - * @var Horde_Imap_Client_Interaction_Pipeline - */ - protected $_pipeline; - - /** - * Server response object. - * - * @var Horde_Imap_Client_Interaction_Server - */ - protected $_server; - - /** - * Constructor. - * - * @param string|null $msg Error message. - * @param integer $code Error code. - * @param Horde_Imap_Client_Interaction_Server $server Server ob. - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline ob. - */ - public function __construct( - $msg, - $code, - Horde_Imap_Client_Interaction_Server $server, - Horde_Imap_Client_Interaction_Pipeline $pipeline - ) - { - $this->details = strval($server->token); - - $this->_pipeline = $pipeline; - $this->_server = $server; - - parent::__construct($msg, $code); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'command': - return ($this->_server instanceof Horde_Imap_Client_Interaction_Server_Tagged) - ? $this->_pipeline->getCmd($this->_server->tag)->getCommand() - : null; - - case 'resp_data': - return $this->_pipeline->data; - - case 'status': - return $this->_server->status; - - default: - return parent::__get($name); - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Exception/Sync.php b/lib/horde/framework/Horde/Imap/Client/Exception/Sync.php deleted file mode 100644 index a53c02fff05..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Exception/Sync.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Exception_Sync extends Horde_Exception_Wrapped -{ - /* Error message codes. */ - - /** - * Token could not be parsed. - */ - const BAD_TOKEN = 1; - - /** - * UIDVALIDITY of the mailbox changed. - */ - const UIDVALIDITY_CHANGED = 2; - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Fetch/Query.php b/lib/horde/framework/Horde/Imap/Client/Fetch/Query.php deleted file mode 100644 index efa35a92d5c..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Fetch/Query.php +++ /dev/null @@ -1,393 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Fetch_Query implements ArrayAccess, Countable, Iterator -{ - /** - * Internal data array. - * - * @var array - */ - protected $_data = array(); - - /** - * Get the full text of the message. - * - * @param array $opts The following options are available: - * - length: (integer) The length of the substring to return. - * DEFAULT: The entire text is returned. - * - peek: (boolean) If set, does not set the '\Seen' flag on the - * message. - * DEFAULT: The seen flag is set. - * - start: (integer) If a portion of the full text is desired to be - * returned, the starting position is identified here. - * DEFAULT: The entire text is returned. - */ - public function fullText(array $opts = array()) - { - $this->_data[Horde_Imap_Client::FETCH_FULLMSG] = $opts; - } - - /** - * Return header text. - * - * Header text is defined only for the base RFC 2822 message or - * message/rfc822 parts. - * - * @param array $opts The following options are available: - * - id: (string) The MIME ID to obtain the header text for. - * DEFAULT: The header text for the base message will be - * returned. - * - length: (integer) The length of the substring to return. - * DEFAULT: The entire text is returned. - * - peek: (boolean) If set, does not set the '\Seen' flag on the - * message. - * DEFAULT: The seen flag is set. - * - start: (integer) If a portion of the full text is desired to be - * returned, the starting position is identified here. - * DEFAULT: The entire text is returned. - */ - public function headerText(array $opts = array()) - { - $id = isset($opts['id']) - ? $opts['id'] - : 0; - $this->_data[Horde_Imap_Client::FETCH_HEADERTEXT][$id] = $opts; - } - - /** - * Return body text. - * - * Body text is defined only for the base RFC 2822 message or - * message/rfc822 parts. - * - * @param array $opts The following options are available: - * - id: (string) The MIME ID to obtain the body text for. - * DEFAULT: The body text for the entire message will be - * returned. - * - length: (integer) The length of the substring to return. - * DEFAULT: The entire text is returned. - * - peek: (boolean) If set, does not set the '\Seen' flag on the - * message. - * DEFAULT: The seen flag is set. - * - start: (integer) If a portion of the full text is desired to be - * returned, the starting position is identified here. - * DEFAULT: The entire text is returned. - */ - public function bodyText(array $opts = array()) - { - $id = isset($opts['id']) - ? $opts['id'] - : 0; - $this->_data[Horde_Imap_Client::FETCH_BODYTEXT][$id] = $opts; - } - - /** - * Return MIME header text. - * - * MIME header text is defined only for non-RFC 2822 messages and - * non-message/rfc822 parts. - * - * @param string $id The MIME ID to obtain the MIME header text for. - * @param array $opts The following options are available: - * - length: (integer) The length of the substring to return. - * DEFAULT: The entire text is returned. - * - peek: (boolean) If set, does not set the '\Seen' flag on the - * message. - * DEFAULT: The seen flag is set. - * - start: (integer) If a portion of the full text is desired to be - * returned, the starting position is identified here. - * DEFAULT: The entire text is returned. - */ - public function mimeHeader($id, array $opts = array()) - { - $this->_data[Horde_Imap_Client::FETCH_MIMEHEADER][$id] = $opts; - } - - /** - * Return the body part data for a MIME ID. - * - * @param string $id The MIME ID to obtain the body part text for. - * @param array $opts The following options are available: - * - decode: (boolean) Attempt to server-side decode the bodypart data - * if it is MIME transfer encoded. - * DEFAULT: false - * - length: (integer) The length of the substring to return. - * DEFAULT: The entire text is returned. - * - peek: (boolean) If set, does not set the '\Seen' flag on the - * message. - * DEFAULT: The seen flag is set. - * - start: (integer) If a portion of the full text is desired to be - * returned, the starting position is identified here. - * DEFAULT: The entire text is returned. - */ - public function bodyPart($id, array $opts = array()) - { - $this->_data[Horde_Imap_Client::FETCH_BODYPART][$id] = $opts; - } - - /** - * Returns the decoded body part size for a MIME ID. - * - * @param string $id The MIME ID to obtain the decoded body part size - * for. - */ - public function bodyPartSize($id) - { - $this->_data[Horde_Imap_Client::FETCH_BODYPARTSIZE][$id] = true; - } - - /** - * Returns RFC 2822 header text that matches a search string. - * - * This header search work only with the base RFC 2822 message or - * message/rfc822 parts. - * - * @param string $label A unique label associated with this particular - * search. This is how the results are stored. - * @param array $search The search string(s) (case-insensitive). - * @param array $opts The following options are available: - * - cache: (boolean) If true, and 'peek' is also true, will cache - * the result of this call. - * DEFAULT: false - * - id: (string) The MIME ID to search. - * DEFAULT: The base message part - * - length: (integer) The length of the substring to return. - * DEFAULT: The entire text is returned. - * - notsearch: (boolean) Do a 'NOT' search on the headers. - * DEFAULT: false - * - peek: (boolean) If set, does not set the '\Seen' flag on the - * message. - * DEFAULT: The seen flag is set. - * - start: (integer) If a portion of the full text is desired to be - * returned, the starting position is identified here. - * DEFAULT: The entire text is returned. - */ - public function headers($label, $search, array $opts = array()) - { - $this->_data[Horde_Imap_Client::FETCH_HEADERS][$label] = array_merge( - $opts, - array( - 'headers' => array_map('strval', $search) - ) - ); - } - - /** - * Return MIME structure information. - */ - public function structure() - { - $this->_data[Horde_Imap_Client::FETCH_STRUCTURE] = true; - } - - /** - * Return envelope header data. - */ - public function envelope() - { - $this->_data[Horde_Imap_Client::FETCH_ENVELOPE] = true; - } - - /** - * Return flags set for the message. - */ - public function flags() - { - $this->_data[Horde_Imap_Client::FETCH_FLAGS] = true; - } - - /** - * Return the internal (IMAP) date of the message. - */ - public function imapDate() - { - $this->_data[Horde_Imap_Client::FETCH_IMAPDATE] = true; - } - - /** - * Return the size (in bytes) of the message. - */ - public function size() - { - $this->_data[Horde_Imap_Client::FETCH_SIZE] = true; - } - - /** - * Return the unique ID of the message. - */ - public function uid() - { - $this->_data[Horde_Imap_Client::FETCH_UID] = true; - } - - /** - * Return the sequence number of the message. - */ - public function seq() - { - $this->_data[Horde_Imap_Client::FETCH_SEQ] = true; - } - - /** - * Return the mod-sequence value for the message. - * - * The server must support the CONDSTORE IMAP extension, and the mailbox - * must support mod-sequences. - */ - public function modseq() - { - $this->_data[Horde_Imap_Client::FETCH_MODSEQ] = true; - } - - /** - * Does the query contain the given criteria? - * - * @param integer $criteria The criteria to remove. - * - * @return boolean True if the query contains the given criteria. - */ - public function contains($criteria) - { - return isset($this->_data[$criteria]); - } - - /** - * Remove an entry under a given criteria. - * - * @param integer $criteria Criteria ID. - * @param string $key The key to remove. - */ - public function remove($criteria, $key) - { - if (isset($this->_data[$criteria]) && - is_array($this->_data[$criteria])) { - unset($this->_data[$criteria][$key]); - if (empty($this->_data[$criteria])) { - unset($this->_data[$criteria]); - } - } - } - - /** - * Returns a hash of the current query object. - * - * @return string Hash. - */ - public function hash() - { - return hash('md5', serialize($this)); - } - - /* ArrayAccess methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) - { - return isset($this->_data[$offset]); - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - return isset($this->_data[$offset]) - ? $this->_data[$offset] - : null; - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - $this->_data[$offset] = $value; - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetUnset($offset) - { - unset($this->_data[$offset]); - } - - /* Countable methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function count() - { - return count($this->_data); - } - - /* Iterator methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function current() - { - $opts = current($this->_data); - - return (!empty($opts) && ($this->key() == Horde_Imap_Client::FETCH_BODYPARTSIZE)) - ? array_keys($opts) - : $opts; - } - - /** - */ - #[ReturnTypeWillChange] - public function key() - { - return key($this->_data); - } - - /** - */ - #[ReturnTypeWillChange] - public function next() - { - next($this->_data); - } - - /** - */ - #[ReturnTypeWillChange] - public function rewind() - { - reset($this->_data); - } - - /** - */ - #[ReturnTypeWillChange] - public function valid() - { - return !is_null($this->key()); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Fetch/Results.php b/lib/horde/framework/Horde/Imap/Client/Fetch/Results.php deleted file mode 100644 index e0cb1e87cee..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Fetch/Results.php +++ /dev/null @@ -1,188 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * - * @property-read integer $key_type The key type (sequence or UID). - */ -class Horde_Imap_Client_Fetch_Results -implements ArrayAccess, Countable, IteratorAggregate -{ - /** - * Key type constants. - */ - const SEQUENCE = 1; - const UID = 2; - - /** - * Internal data array. - * - * @var array - */ - protected $_data = array(); - - /** - * Key type. - * - * @var integer - */ - protected $_keyType; - - /** - * Class to use when creating a new fetch object. - * - * @var string - */ - protected $_obClass; - - /** - * Constructor. - * - * @param string $ob_class Class to use when creating a new fetch - * object. - * @param integer $key_type Key type. - */ - public function __construct($ob_class = 'Horde_Imap_Client_Data_Fetch', - $key_type = self::UID) - { - $this->_obClass = $ob_class; - $this->_keyType = $key_type; - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'key_type': - return $this->_keyType; - } - } - - /** - * Return a fetch object, creating and storing an empty object in the - * results set if it doesn't currently exist. - * - * @param string $key The key to retrieve. - * - * @return Horde_Imap_Client_Data_Fetch The fetch object. - */ - public function get($key) - { - if (!isset($this->_data[$key])) { - $this->_data[$key] = new $this->_obClass(); - } - - return $this->_data[$key]; - } - - /** - * Return the list of IDs. - * - * @return array ID list. - */ - public function ids() - { - ksort($this->_data); - return array_keys($this->_data); - } - - /** - * Return the first fetch object in the results, if there is only one - * object. - * - * @return null|Horde_Imap_Client_Data_Fetch The fetch object if there is - * only one object, or null. - */ - public function first() - { - return (count($this->_data) === 1) - ? reset($this->_data) - : null; - } - - /** - * Clears all fetch results. - * - * @since 2.6.0 - */ - public function clear() - { - $this->_data = array(); - } - - /* ArrayAccess methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) - { - return isset($this->_data[$offset]); - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - return isset($this->_data[$offset]) - ? $this->_data[$offset] - : null; - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - $this->_data[$offset] = $value; - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetUnset($offset) - { - unset($this->_data[$offset]); - } - - /* Countable methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function count() - { - return count($this->_data); - } - - /* IteratorAggregate methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function getIterator() - { - ksort($this->_data); - return new ArrayIterator($this->_data); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Ids.php b/lib/horde/framework/Horde/Imap/Client/Ids.php deleted file mode 100644 index f70c5c8f466..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Ids.php +++ /dev/null @@ -1,511 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * - * @property-read boolean $all Does this represent an ALL message set? - * @property-read array $ids The list of IDs. - * @property-read boolean $largest Does this represent the largest ID in use? - * @property-read string $max The largest ID (@since 2.20.0). - * @property-read string $min The smallest ID (@since 2.20.0). - * @property-read string $range_string Generates a range string consisting of - * all messages between begin and end of - * ID list. - * @property-read boolean $search_res Does this represent a search result? - * @property-read boolean $sequence Are these sequence IDs? If false, these - * are UIDs. - * @property-read boolean $special True if this is a "special" ID - * representation. - * @property-read string $tostring Return the non-sorted string - * representation. - * @property-read string $tostring_sort Return the sorted string - * representation. - */ -class Horde_Imap_Client_Ids implements Countable, Iterator, Serializable -{ - /** - * "Special" representation constants. - */ - const ALL = "\01"; - const SEARCH_RES = "\02"; - const LARGEST = "\03"; - - /** - * Allow duplicate IDs? - * - * @var boolean - */ - public $duplicates = false; - - /** - * List of IDs. - * - * @var mixed - */ - protected $_ids = array(); - - /** - * Are IDs message sequence numbers? - * - * @var boolean - */ - protected $_sequence = false; - - /** - * Are IDs sorted? - * - * @var boolean - */ - protected $_sorted = false; - - /** - * Constructor. - * - * @param mixed $ids See self::add(). - * @param boolean $sequence Are $ids message sequence numbers? - */ - public function __construct($ids = null, $sequence = false) - { - $this->add($ids); - $this->_sequence = $sequence; - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'all': - return ($this->_ids === self::ALL); - - case 'ids': - return is_array($this->_ids) - ? $this->_ids - : array(); - - case 'largest': - return ($this->_ids === self::LARGEST); - - case 'max': - $this->sort(); - return end($this->_ids); - - case 'min': - $this->sort(); - return reset($this->_ids); - - case 'range_string': - if (!count($this)) { - return ''; - } - - $min = $this->min; - $max = $this->max; - - return ($min == $max) - ? $min - : $min . ':' . $max; - - case 'search_res': - return ($this->_ids === self::SEARCH_RES); - - case 'sequence': - return (bool)$this->_sequence; - - case 'special': - return is_string($this->_ids); - - case 'tostring': - case 'tostring_sort': - if ($this->all) { - return '1:*'; - } elseif ($this->largest) { - return '*'; - } elseif ($this->search_res) { - return '$'; - } - return strval($this->_toSequenceString($name == 'tostring_sort')); - } - } - - /** - */ - public function __toString() - { - return $this->tostring; - } - - /** - * Add IDs to the current object. - * - * @param mixed $ids Either self::ALL, self::SEARCH_RES, self::LARGEST, - * Horde_Imap_Client_Ids object, array, or sequence - * string. - */ - public function add($ids) - { - if (!is_null($ids)) { - if (is_string($ids) && - in_array($ids, array(self::ALL, self::SEARCH_RES, self::LARGEST))) { - $this->_ids = $ids; - } elseif ($add = $this->_resolveIds($ids)) { - if (is_array($this->_ids) && !empty($this->_ids)) { - foreach ($add as $val) { - $this->_ids[] = $val; - } - } else { - $this->_ids = $add; - } - if (!$this->duplicates) { - $this->_ids = (count($this->_ids) > 25000) - ? array_unique($this->_ids) - : array_keys(array_flip($this->_ids)); - } - } - - $this->_sorted = is_array($this->_ids) && (count($this->_ids) === 1); - } - } - - /** - * Removed IDs from the current object. - * - * @since 2.17.0 - * - * @param mixed $ids Either Horde_Imap_Client_Ids object, array, or - * sequence string. - */ - public function remove($ids) - { - if (!$this->isEmpty() && - ($remove = $this->_resolveIds($ids))) { - $this->_ids = array_diff($this->_ids, array_unique($remove)); - } - } - - /** - * Is this object empty (i.e. does not contain IDs)? - * - * @return boolean True if object is empty. - */ - public function isEmpty() - { - return (is_array($this->_ids) && !count($this->_ids)); - } - - /** - * Reverses the order of the IDs. - */ - public function reverse() - { - if (is_array($this->_ids)) { - $this->_ids = array_reverse($this->_ids); - } - } - - /** - * Sorts the IDs. - */ - public function sort() - { - if (!$this->_sorted && is_array($this->_ids)) { - $this->_sort($this->_ids); - $this->_sorted = true; - } - } - - /** - * Sorts the IDs numerically. - * - * @param array $ids The array list. - */ - protected function _sort(&$ids) - { - sort($ids, SORT_NUMERIC); - } - - /** - * Split the sequence string at an approximate length. - * - * @since 2.7.0 - * - * @param integer $length Length to split. - * - * @return array A list containing individual sequence strings. - */ - public function split($length) - { - $id = new Horde_Stream_Temp(); - $id->add($this->tostring_sort, true); - - $out = array(); - - do { - $out[] = $id->substring(0, $length) . $id->getToChar(','); - } while (!$id->eof()); - - return $out; - } - - /** - * Resolve the $ids input to add() and remove(). - * - * @param mixed $ids Either Horde_Imap_Client_Ids object, array, or - * sequence string. - * - * @return array An array of IDs. - */ - protected function _resolveIds($ids) - { - if ($ids instanceof Horde_Imap_Client_Ids) { - return $ids->ids; - } elseif (is_array($ids)) { - return $ids; - } elseif (is_string($ids) || is_integer($ids)) { - return is_numeric($ids) - ? array($ids) - : $this->_fromSequenceString($ids); - } - - return array(); - } - - /** - * Create an IMAP message sequence string from a list of indices. - * - * Index Format: range_start:range_end,uid,uid2,... - * - * @param boolean $sort Numerically sort the IDs before creating the - * range? - * - * @return string The IMAP message sequence string. - */ - protected function _toSequenceString($sort = true) - { - if (empty($this->_ids)) { - return ''; - } - - $in = $this->_ids; - - if ($sort && !$this->_sorted) { - $this->_sort($in); - } - - $first = $last = array_shift($in); - $i = count($in) - 1; - $out = array(); - - foreach ($in as $key => $val) { - if (($last + 1) == $val) { - $last = $val; - } - - if (($i == $key) || ($last != $val)) { - if ($last == $first) { - $out[] = $first; - if ($i == $key) { - $out[] = $val; - } - } else { - $out[] = $first . ':' . $last; - if (($i == $key) && ($last != $val)) { - $out[] = $val; - } - } - $first = $last = $val; - } - } - - return empty($out) - ? $first - : implode(',', $out); - } - - /** - * Parse an IMAP message sequence string into a list of indices. - * - * @see _toSequenceString() - * - * @param string $str The IMAP message sequence string. - * - * @return array An array of indices. - */ - protected function _fromSequenceString($str) - { - $ids = array(); - $str = trim($str); - - if (!strlen($str)) { - return $ids; - } - - $idarray = explode(',', $str); - - foreach ($idarray as $val) { - $range = explode(':', $val); - if (isset($range[1])) { - for ($i = min($range), $j = max($range); $i <= $j; ++$i) { - $ids[] = $i; - } - } else { - $ids[] = $val; - } - } - - return $ids; - } - - /* Countable methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function count() - { - return is_array($this->_ids) - ? count($this->_ids) - : 0; - } - - /* Iterator methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function current() - { - return is_array($this->_ids) - ? current($this->_ids) - : null; - } - - /** - */ - #[ReturnTypeWillChange] - public function key() - { - return is_array($this->_ids) - ? key($this->_ids) - : null; - } - - /** - */ - #[ReturnTypeWillChange] - public function next() - { - if (is_array($this->_ids)) { - next($this->_ids); - } - } - - /** - */ - #[ReturnTypeWillChange] - public function rewind() - { - if (is_array($this->_ids)) { - reset($this->_ids); - } - } - - /** - */ - #[ReturnTypeWillChange] - public function valid() - { - return !is_null($this->key()); - } - - public function serialize() - { - return serialize($this->__serialize()); - } - - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version change.'); - } - - $this->__unserialize($data); - } - - /** - */ - public function __serialize() - { - $save = array(); - - if ($this->duplicates) { - $save['d'] = 1; - } - - if ($this->_sequence) { - $save['s'] = 1; - } - - if ($this->_sorted) { - $save['is'] = 1; - } - - switch ($this->_ids) { - case self::ALL: - $save['a'] = true; - break; - - case self::LARGEST: - $save['l'] = true; - break; - - case self::SEARCH_RES: - $save['sr'] = true; - break; - - default: - $save['i'] = strval($this); - break; - } - - return $save; - } - - /** - */ - public function __unserialize($data) - { - $this->duplicates = !empty($data['d']); - $this->_sequence = !empty($data['s']); - $this->_sorted = !empty($data['is']); - - if (isset($data['a'])) { - $this->_ids = self::ALL; - } elseif (isset($data['l'])) { - $this->_ids = self::LARGEST; - } elseif (isset($data['sr'])) { - $this->_ids = self::SEARCH_RES; - } elseif (isset($data['i'])) { - $this->add($data['i']); - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Ids/Map.php b/lib/horde/framework/Horde/Imap/Client/Ids/Map.php deleted file mode 100644 index b2b6f87704a..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Ids/Map.php +++ /dev/null @@ -1,256 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.1.0 - * - * @property-read array $map The raw ID mapping data. - * @property-read Horde_Imap_Client_Ids $seq The sorted sequence values. - * @property-read Horde_Imap_Client_Ids $uids The sorted UIDs. - */ -class Horde_Imap_Client_Ids_Map implements Countable, IteratorAggregate, Serializable -{ - /** - * Sequence -> UID mapping. - * - * @var array - */ - protected $_ids = array(); - - /** - * Is the array sorted? - * - * @var boolean - */ - protected $_sorted = true; - - /** - * Constructor. - * - * @param array $ids Array of sequence -> UID mapping. - */ - public function __construct(array $ids = array()) - { - $this->update($ids); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'map': - return $this->_ids; - - case 'seq': - $this->sort(); - return new Horde_Imap_Client_Ids(array_keys($this->_ids), true); - - case 'uids': - $this->sort(); - return new Horde_Imap_Client_Ids($this->_ids); - } - } - - /** - * Updates the mapping. - * - * @param array $ids Array of sequence -> UID mapping. - * - * @return boolean True if the mapping changed. - */ - public function update($ids) - { - if (empty($ids)) { - return false; - } elseif (empty($this->_ids)) { - $this->_ids = $ids; - $change = true; - } else { - $change = false; - foreach ($ids as $k => $v) { - if (!isset($this->_ids[$k]) || ($this->_ids[$k] != $v)) { - $this->_ids[$k] = $v; - $change = true; - } - } - } - - if ($change) { - $this->_sorted = false; - } - - return $change; - } - - /** - * Create a Sequence <-> UID lookup table. - * - * @param Horde_Imap_Client_Ids $ids IDs to lookup. - * - * @return array Keys are sequence numbers, values are UIDs. - */ - public function lookup(Horde_Imap_Client_Ids $ids) - { - if ($ids->all) { - return $this->_ids; - } elseif ($ids->sequence) { - return array_intersect_key($this->_ids, array_flip($ids->ids)); - } - - return array_intersect($this->_ids, $ids->ids); - } - - /** - * Removes messages from the ID mapping. - * - * @param Horde_Imap_Client_Ids $ids IDs to remove. - */ - public function remove(Horde_Imap_Client_Ids $ids) - { - /* For sequence numbers, we need to reindex anytime we have an index - * that appears equal to or after a previously seen index. If an IMAP - * server is smart, it will expunge in reverse order instead. */ - if ($ids->sequence) { - $remove = $ids->ids; - } else { - $ids->sort(); - $remove = array_reverse(array_keys($this->lookup($ids))); - } - - if (empty($remove)) { - return; - } - - $this->sort(); - - if (count($remove) == count($this->_ids) && - !array_diff($remove, array_keys($this->_ids))) { - $this->_ids = array(); - return; - } - - /* Find the minimum sequence number to remove. We know entries before - * this are untouched so no need to process them multiple times. */ - $first = min($remove); - $edit = $newids = array(); - foreach (array_keys($this->_ids) as $i => $seq) { - if ($seq >= $first) { - $i += (($seq == $first) ? 0 : 1); - $newids = array_slice($this->_ids, 0, $i, true); - $edit = array_slice($this->_ids, $i + (($seq == $first) ? 0 : 1), null, true); - break; - } - } - - if (!empty($edit)) { - foreach ($remove as $val) { - $found = false; - $tmp = array(); - - foreach (array_keys($edit) as $i => $seq) { - if ($found) { - $tmp[$seq - 1] = $edit[$seq]; - } elseif ($seq >= $val) { - $tmp = array_slice($edit, 0, ($seq == $val) ? $i : $i + 1, true); - $found = true; - } - } - - $edit = $tmp; - } - } - - $this->_ids = $newids + $edit; - } - - /** - * Sort the map. - */ - public function sort() - { - if (!$this->_sorted) { - ksort($this->_ids, SORT_NUMERIC); - $this->_sorted = true; - } - } - - /* Countable methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function count() - { - return count($this->_ids); - } - - /* IteratorAggregate method. */ - - /** - */ - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_ids); - } - - /* Serializable methods. */ - - public function serialize() - { - return serialize($this->__serialize()); - } - - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version change.'); - } - $this->__unserialize($data); - } - - /** - */ - public function __serialize() - { - /* Sort before storing; provides more compressible representation. */ - $this->sort(); - - return [ - strval(new Horde_Imap_Client_Ids(array_keys($this->_ids))), - strval(new Horde_Imap_Client_Ids(array_values($this->_ids))) - ]; - } - - /** - */ - public function __unserialize($data) - { - $keys = new Horde_Imap_Client_Ids($data[0]); - $vals = new Horde_Imap_Client_Ids($data[1]); - $this->_ids = array_combine($keys->ids, $vals->ids); - - /* Guaranteed to be sorted if unserializing. */ - $this->_sorted = true; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Ids/Pop3.php b/lib/horde/framework/Horde/Imap/Client/Ids/Pop3.php deleted file mode 100644 index 48120378e33..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Ids/Pop3.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Ids_Pop3 extends Horde_Imap_Client_Ids -{ - /** - */ - protected function _sort(&$ids) - { - /* There is no guarantee of POP3 UIDL order - IDs need to be unique, - * but there is no requirement they need be incrementing. RFC - * 1939[7] */ - } - - /** - * Create a POP3 message sequence string. - * - * Index Format: UID1[SPACE]UID2... - * - * @param boolean $sort Not used in this class. - * - * @return string The POP3 message sequence string. - */ - protected function _toSequenceString($sort = true) - { - /* $sort is ignored - see _sort(). */ - - /* Use space as delimiter as it is the only printable ASCII character - * that is not allowed as part of the UID (RFC 1939 [7]). */ - return implode(' ', count($this->_ids) > 25000 ? array_unique($this->_ids) : array_keys(array_flip($this->_ids))); - } - - /** - * Parse a POP3 message sequence string into a list of indices. - * - * @param string $str The POP3 message sequence string. - * - * @return array An array of UIDs. - */ - protected function _fromSequenceString($str) - { - return explode(' ', trim($str)); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Interaction/Client.php b/lib/horde/framework/Horde/Imap/Client/Interaction/Client.php deleted file mode 100644 index f0f8c19208d..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Interaction/Client.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @category Horde - * @copyright 2012-2016 Horde LLC - * @deprecated - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Interaction_Client extends Horde_Imap_Client_Data_Format_List -{ - /** - * The command tag. - * - * @var string - */ - public $tag; - - /** - * Constructor. - * - * @param string $tag The tag to use. If not set, will be automatically - * generated. - */ - public function __construct($tag = null) - { - $this->tag = is_null($tag) - ? substr(strval(new Horde_Support_Randomid()), 0, 10) - : strval($tag); - - parent::__construct($this->tag); - } - - /** - * Get the command. - * - * @return string The command. - */ - public function getCommand() - { - return isset($this->_data[1]) - ? $this->_data[1] - : null; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Interaction/Command.php b/lib/horde/framework/Horde/Imap/Client/Interaction/Command.php deleted file mode 100644 index 3f5f2ac893e..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Interaction/Command.php +++ /dev/null @@ -1,184 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.10.0 - * - * @property-read boolean $continuation True if the command requires a server - * continuation response. - */ -class Horde_Imap_Client_Interaction_Command -extends Horde_Imap_Client_Data_Format_List -{ - /** - * Debug string(s) to use instead of command text. - * - * Multiple entries refer to the various steps in a continuation command. - * - * @var array - */ - public $debug = array(); - - /** - * Use LITERAL+ if available - * - * @var boolean - */ - public $literalplus = true; - - /** - * Are literal8's available? - * - * @var boolean - */ - public $literal8 = false; - - /** - * A callback to run on error. - * - * If callback returns true, the command will be treated as successful. - * - * @since 2.24.0 - * - * @var callback - */ - public $on_error = null; - - /** - * A callback to run on success. - * - * @since 2.28.0 - * - * @var callback - */ - public $on_success = null; - - /** - * Pipeline object associated with this command. - * - * @since 2.28.0 - * - * @var Horde_Imap_Client_Interaction_Pipeline - */ - public $pipeline; - - /** - * Server response. - * - * @var Horde_Imap_Client_Interaction_Server - */ - public $response; - - /** - * The command tag. - * - * @var string - */ - public $tag; - - /** - * Command timer. - * - * @var Horde_Support_Timer - */ - protected $_timer; - - /** - * Constructor. - * - * @param string $cmd The IMAP command. - * @param string $tag The tag to use. If not set, will be automatically - * generated. - */ - public function __construct($cmd, $tag = null) - { - $this->tag = is_null($tag) - ? substr(new Horde_Support_Randomid(), 0, 10) - : strval($tag); - - parent::__construct($this->tag); - - $this->add($cmd); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'continuation': - return $this->_continuationCheck($this); - } - } - - /** - * Get the command. - * - * @return string The command. - */ - public function getCommand() - { - return $this->_data[1]; - } - - /** - * Start the command timer. - */ - public function startTimer() - { - $this->_timer = new Horde_Support_Timer(); - $this->_timer->push(); - } - - /** - * Return the timer data. - * - * @return mixed Null if timer wasn't started, or a float containing - * elapsed command time. - */ - public function getTimer() - { - return $this->_timer - ? round($this->_timer->pop(), 4) - : null; - } - - /** - * Recursive check for continuation functions. - */ - protected function _continuationCheck($list) - { - foreach ($list as $val) { - if (($val instanceof Horde_Imap_Client_Interaction_Command_Continuation) || - (($val instanceof Horde_Imap_Client_Data_Format_String) && - $val->literal())) { - return true; - } - - if (($val instanceof Horde_Imap_Client_Data_Format_List) && - $this->_continuationCheck($val)) { - return true; - } - } - - return false; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Interaction/Command/Continuation.php b/lib/horde/framework/Horde/Imap/Client/Interaction/Command/Continuation.php deleted file mode 100644 index bb894a915ed..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Interaction/Command/Continuation.php +++ /dev/null @@ -1,74 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.10.0 - */ -class Horde_Imap_Client_Interaction_Command_Continuation -{ - /** - * Is this an optional continuation request? - * - * @since 2.13.0 - * @var boolean - */ - public $optional = false; - - /** - * Closure function to run after continuation response. - * - * @var Closure - */ - protected $_closure; - - /** - * Constructor. - * - * @param Closure $closure A function to run after the continuation - * response is received. It receives one - * argument - a Continuation object - and should - * return a list of arguments to send to the - * server (via a - * Horde_Imap_Client_Data_Format_List object). - */ - public function __construct($closure) - { - $this->_closure = $closure; - } - - /** - * Calls the closure object. - * - * @param Horde_Imap_Client_Interaction_Server_Continuation $ob Continuation - * object. - * - * @return Horde_Imap_Client_Data_Format_List Further commands to issue - * to the server. - */ - public function getCommands( - Horde_Imap_Client_Interaction_Server_Continuation $ob - ) - { - $closure = $this->_closure; - return $closure($ob); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Interaction/Pipeline.php b/lib/horde/framework/Horde/Imap/Client/Interaction/Pipeline.php deleted file mode 100644 index 1c99a9a1506..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Interaction/Pipeline.php +++ /dev/null @@ -1,162 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.10.0 - * - * @property-read boolean $finished True if all commands have finished. - */ -class Horde_Imap_Client_Interaction_Pipeline implements Countable, IteratorAggregate -{ - /** - * Data storage from server responses. - * - * @var array - */ - public $data = array( - 'modseqs' => array(), - 'modseqs_nouid' => array() - ); - - /** - * Fetch results. - * - * @var Horde_Imap_Client_Fetch_Results - */ - public $fetch; - - /** - * The list of commands. - * - * @var array - */ - protected $_commands = array(); - - /** - * The list of commands to complete. - * - * @var array - */ - protected $_todo = array(); - - /** - * Constructor. - * - * @param Horde_Imap_Client_Fetch_Results $fetch Fetch results object. - */ - public function __construct(Horde_Imap_Client_Fetch_Results $fetch) - { - $this->fetch = $fetch; - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'finished': - return empty($this->_todo); - } - } - - /** - * Add a command to the pipeline. - * - * @param Horde_Imap_Client_Interaction_Command $cmd Command object. - * @param boolean $top Add command to top - * of queue? - */ - public function add(Horde_Imap_Client_Interaction_Command $cmd, - $top = false) - { - if ($top) { - // This won't re-index keys, which may be numerical. - $this->_commands = array($cmd->tag => $cmd) + $this->_commands; - } else { - $this->_commands[$cmd->tag] = $cmd; - } - $this->_todo[$cmd->tag] = true; - } - - /** - * Mark a command as completed. - * - * @param Horde_Imap_Client_Interaction_Server_Tagged $resp Tagged server - * response. - * - * @return Horde_Imap_Client_Interaction_Command Command that was - * completed. Returns null - * if tagged response - * is not contained in this - * pipeline object. - */ - public function complete(Horde_Imap_Client_Interaction_Server_Tagged $resp) - { - if (isset($this->_commands[$resp->tag])) { - $cmd = $this->_commands[$resp->tag]; - $cmd->response = $resp; - unset($this->_todo[$resp->tag]); - } else { - /* This can be reached if a previous pipeline action was aborted, - * e.g. via an Exception. */ - $cmd = null; - } - - return $cmd; - } - - /** - * Return the command for a given tag. - * - * @param string $tag The command tag. - * - * @return Horde_Imap_Client_Interaction_Command A command object (or - * null if the tag does - * not exist). - */ - public function getCmd($tag) - { - return isset($this->_commands[$tag]) - ? $this->_commands[$tag] - : null; - } - - /* Countable methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function count() - { - return count($this->_commands); - } - - /* IteratorAggregate methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_commands); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Interaction/Server.php b/lib/horde/framework/Horde/Imap/Client/Interaction/Server.php deleted file mode 100644 index ded6ad6a64f..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Interaction/Server.php +++ /dev/null @@ -1,144 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Interaction_Server -{ - /** - * Response codes (RFC 3501 [7.1]). - */ - const BAD = 1; - const BYE = 2; - const NO = 3; - const OK = 4; - const PREAUTH = 5; - - /** - * Check for status response? - * - * @var boolean - */ - protected $_checkStatus = true; - - /** - * Response code (RFC 3501 [7.1]). Properties: - * - code: (string) Response code. - * - data: (array) Data associated with response. - * - * @var object - */ - public $responseCode = null; - - /** - * Status response from the server. - * - * @var string - */ - public $status = null; - - /** - * IMAP server data. - * - * @var Horde_Imap_Client_Tokenize - */ - public $token; - - /** - * Auto-scan an incoming line to determine the response type. - * - * @param Horde_Imap_Client_Tokenize $t Tokenized data returned from the - * server. - * - * @return Horde_Imap_Client_Interaction_Server A server response object. - */ - public static function create(Horde_Imap_Client_Tokenize $t) - { - $t->rewind(); - $tag = $t->next(); - $t->next(); - - switch ($tag) { - case '+': - return new Horde_Imap_Client_Interaction_Server_Continuation($t); - - case '*': - return new Horde_Imap_Client_Interaction_Server_Untagged($t); - - default: - return new Horde_Imap_Client_Interaction_Server_Tagged($t, $tag); - } - } - - /** - * Constructor. - * - * @param Horde_Imap_Client_Tokenize $token Tokenized data returned from - * the server. - */ - public function __construct(Horde_Imap_Client_Tokenize $token) - { - $this->token = $token; - - /* Check for response status. */ - $status = $token->current(); - $valid = array('BAD', 'BYE', 'NO', 'OK', 'PREAUTH'); - - if (in_array($status, $valid)) { - $this->status = constant(__CLASS__ . '::' . $status); - $resp_text = $token->next(); - - /* Check for response code. Only occurs if there is a response - * status. */ - if (is_string($resp_text) && ($resp_text[0] === '[')) { - $resp = new stdClass; - $resp->data = array(); - - if ($resp_text[strlen($resp_text) - 1] === ']') { - $resp->code = substr($resp_text, 1, -1); - } else { - $resp->code = substr($resp_text, 1); - - while (($elt = $token->next()) !== false) { - if (is_string($elt) && $elt[strlen($elt) - 1] === ']') { - $resp->data[] = substr($elt, 0, -1); - break; - } - $resp->data[] = is_string($elt) - ? $elt - : $token->flushIterator(); - } - } - - $token->next(); - $this->responseCode = $resp; - } - } - } - - /** - */ - public function __toString() - { - return strval($this->token); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Interaction/Server/Continuation.php b/lib/horde/framework/Horde/Imap/Client/Interaction/Server/Continuation.php deleted file mode 100644 index 04a44391ec8..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Interaction/Server/Continuation.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Interaction_Server_Continuation extends Horde_Imap_Client_Interaction_Server -{ -} diff --git a/lib/horde/framework/Horde/Imap/Client/Interaction/Server/Tagged.php b/lib/horde/framework/Horde/Imap/Client/Interaction/Server/Tagged.php deleted file mode 100644 index 6fff744daf6..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Interaction/Server/Tagged.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Interaction_Server_Tagged -extends Horde_Imap_Client_Interaction_Server -{ - /** - * Tag. - * - * @var string - */ - public $tag; - - /** - * @param string $tag Response tag. - */ - public function __construct(Horde_Imap_Client_Tokenize $token, $tag) - { - $this->tag = $tag; - - parent::__construct($token); - - if (is_null($this->status)) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Bad tagged response.") - ); - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Interaction/Server/Untagged.php b/lib/horde/framework/Horde/Imap/Client/Interaction/Server/Untagged.php deleted file mode 100644 index 479096ae116..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Interaction/Server/Untagged.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Interaction_Server_Untagged extends Horde_Imap_Client_Interaction_Server -{ -} diff --git a/lib/horde/framework/Horde/Imap/Client/Mailbox.php b/lib/horde/framework/Horde/Imap/Client/Mailbox.php deleted file mode 100644 index 0064274c48f..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Mailbox.php +++ /dev/null @@ -1,164 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * - * @property-read string $list_escape Escapes mailbox for use in LIST - * command (UTF-8). - * @property-read string $utf7imap Mailbox in UTF7-IMAP. - * @property-read string $utf8 Mailbox in UTF-8. - */ -class Horde_Imap_Client_Mailbox implements Serializable -{ - /** - * UTF7-IMAP representation of mailbox. - * If boolean true, it is identical to UTF-8 representation. - * - * @var mixed - */ - protected $_utf7imap; - - /** - * UTF8 representation of mailbox. - * - * @var string - */ - protected $_utf8; - - /** - * Shortcut to obtaining mailbox object. - * - * @param string $mbox The mailbox name. - * @param boolean $utf7imap Is mailbox UTF7-IMAP encoded? Otherwise, - * mailbox is assumed to be UTF-8. - * - * @return Horde_Imap_Client_Mailbox A mailbox object. - */ - public static function get($mbox, $utf7imap = false) - { - return ($mbox instanceof Horde_Imap_Client_Mailbox) - ? $mbox - : new Horde_Imap_Client_Mailbox($mbox, $utf7imap); - } - - /** - * Constructor. - * - * @param string $mbox The mailbox name. - * @param boolean $utf7imap Is mailbox UTF7-IMAP encoded (true). - * Otherwise, mailbox is assumed to be UTF-8 - * encoded. - */ - public function __construct($mbox, $utf7imap = false) - { - if (strcasecmp($mbox, 'INBOX') === 0) { - $mbox = 'INBOX'; - } - - if ($utf7imap) { - $this->_utf7imap = $mbox; - } else { - $this->_utf8 = $mbox; - } - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'list_escape': - return preg_replace("/\*+/", '%', $this->utf8); - - case 'utf7imap': - if (!isset($this->_utf7imap)) { - $n = Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($this->_utf8); - $this->_utf7imap = ($n == $this->_utf8) - ? true - : $n; - } - - return ($this->_utf7imap === true) - ? $this->_utf8 - : $this->_utf7imap; - - case 'utf8': - if (!isset($this->_utf8)) { - $this->_utf8 = Horde_Imap_Client_Utf7imap::Utf7ImapToUtf8($this->_utf7imap); - if ($this->_utf8 == $this->_utf7imap) { - $this->_utf7imap = true; - } - } - return (string)$this->_utf8; - } - } - - /** - */ - public function __toString() - { - return $this->utf8; - } - - /** - * Compares this mailbox to another mailbox string. - * - * @return boolean True if the items are equal. - */ - public function equals($mbox) - { - return ($this->utf8 == $mbox); - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache value changed.'); - } - $this->__unserialize($data); - } - - /** - * @return array - */ - public function __serialize() - { - return [$this->_utf7imap, $this->_utf8]; - } - - public function __unserialize(array $data) - { - list($this->_utf7imap, $this->_utf8) = $data; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Mailbox/List.php b/lib/horde/framework/Horde/Imap/Client/Mailbox/List.php deleted file mode 100644 index d64498178bc..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Mailbox/List.php +++ /dev/null @@ -1,160 +0,0 @@ - - * @category Horde - * @copyright 2004-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Mailbox_List implements Countable, IteratorAggregate -{ - /** - * The delimiter character to use. - * - * @var string - */ - protected $_delimiter; - - /** - * Mailbox list. - * - * @var array - */ - protected $_mboxes = array(); - - /** - * Should we sort with INBOX at the front of the list? - * - * @var boolean - */ - protected $_sortinbox; - - /** - * Constructor. - * - * @param mixed $mboxes A mailbox or list of mailboxes. - */ - public function __construct($mboxes) - { - $this->_mboxes = is_array($mboxes) - ? $mboxes - : array($mboxes); - } - - /** - * Sort the list of mailboxes. - * - * @param array $opts Options: - * - delimiter: (string) The delimiter to use. - * DEFAULT: '.' - * - inbox: (boolean) Always put INBOX at the head of the list? - * DEFAULT: Yes - * - noupdate: (boolean) Do not update the object's mailbox list? - * DEFAULT: true - * - * @return array List of sorted mailboxes (index association is kept). - */ - public function sort(array $opts = array()) - { - $this->_delimiter = isset($opts['delimiter']) - ? $opts['delimiter'] - : '.'; - $this->_sortinbox = (!isset($opts['inbox']) || !empty($opts['inbox'])); - - if (empty($opts['noupdate'])) { - $mboxes = &$this->_mboxes; - } else { - $mboxes = $this->_mboxes; - } - - uasort($mboxes, array($this, '_mboxCompare')); - - return $mboxes; - } - - /** - * Hierarchical folder sorting function (used with usort()). - * - * @param string $a Comparison item 1. - * @param string $b Comparison item 2. - * - * @return integer See usort(). - */ - final protected function _mboxCompare($a, $b) - { - /* Always return INBOX as "smaller". */ - if ($this->_sortinbox) { - if (strcasecmp($a, 'INBOX') === 0) { - return -1; - } elseif (strcasecmp($b, 'INBOX') === 0) { - return 1; - } - } - - $a_parts = explode($this->_delimiter, $a); - $b_parts = explode($this->_delimiter, $b); - - $a_count = count($a_parts); - $b_count = count($b_parts); - - for ($i = 0, $iMax = min($a_count, $b_count); $i < $iMax; ++$i) { - if ($a_parts[$i] != $b_parts[$i]) { - /* If only one of the folders is under INBOX, return it as - * "smaller". */ - if ($this->_sortinbox && ($i === 0)) { - $a_base = (strcasecmp($a_parts[0], 'INBOX') === 0); - $b_base = (strcasecmp($b_parts[0], 'INBOX') === 0); - if ($a_base && !$b_base) { - return -1; - } elseif (!$a_base && $b_base) { - return 1; - } - } - - $cmp = strnatcasecmp($a_parts[$i], $b_parts[$i]); - return ($cmp === 0) - ? strcmp($a_parts[$i], $b_parts[$i]) - : $cmp; - } elseif ($a_parts[$i] !== $b_parts[$i]) { - return strlen($a_parts[$i]) - strlen($b_parts[$i]); - } - } - - return ($a_count - $b_count); - } - - /* Countable methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function count() - { - return count($this->_mboxes); - } - - /* IteratorAggregate methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_mboxes); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Namespace/List.php b/lib/horde/framework/Horde/Imap/Client/Namespace/List.php deleted file mode 100644 index 7c394204c54..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Namespace/List.php +++ /dev/null @@ -1,136 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.21.0 - */ -class Horde_Imap_Client_Namespace_List -implements ArrayAccess, Countable, IteratorAggregate -{ - /** - * The list of namespace objects. - * - * @var array - */ - protected $_ns = array(); - - /** - * Constructor. - * - * @param array $ns The list of namespace objects. - */ - public function __construct($ns = array()) - { - foreach ($ns as $val) { - $this->_ns[strval($val)] = $val; - } - } - - /** - * Get namespace info for a full mailbox path. - * - * @param string $mbox The mailbox path. - * @param boolean $personal If true, will return the empty namespace only - * if it is a personal namespace. - * - * @return mixed The Horde_Imap_Client_Data_Namespace object for the - * mailbox path, or null if the path doesn't exist. - */ - public function getNamespace($mbox, $personal = false) - { - $mbox = strval($mbox); - - if ($ns = $this[$mbox]) { - return $ns; - } - - foreach ($this->_ns as $val) { - $mbox = $mbox . $val->delimiter; - if (strlen($val->name) && (strpos($mbox, $val->name) === 0)) { - return $val; - } - } - - return (($ns = $this['']) && (!$personal || ($ns->type === $ns::NS_PERSONAL))) - ? $ns - : null; - } - - /* ArrayAccess methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) - { - return isset($this->_ns[strval($offset)]); - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - $offset = strval($offset); - - return isset($this->_ns[$offset]) - ? $this->_ns[$offset] - : null; - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - if ($value instanceof Horde_Imap_Client_Data_Namespace) { - $this->_ns[strval($value)] = $value; - } - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetUnset($offset) - { - unset($this->_ns[strval($offset)]); - } - - /* Countable methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function count() - { - return count($this->_ns); - } - - /* IteratorAggregate methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_ns); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Password/Xoauth2.php b/lib/horde/framework/Horde/Imap/Client/Password/Xoauth2.php deleted file mode 100644 index 3c32a7a853a..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Password/Xoauth2.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.16.0 - */ -class Horde_Imap_Client_Password_Xoauth2 -implements Horde_Imap_Client_Base_Password -{ - /** - * Access token. - * - * @var string - */ - public $access_token; - - /** - * Username. - * - * @var string - */ - public $username; - - /** - * Constructor. - * - * @param string $username The username. - * @param string $access_token The access token. - */ - public function __construct($username, $access_token) - { - $this->username = $username; - $this->access_token = $access_token; - } - - /** - * Return the password to use for the server connection. - * - * @return string The password. - */ - public function getPassword() - { - // base64("user=" {User} "^Aauth=Bearer " {Access Token} "^A^A") - // ^A represents a Control+A (\001) - return base64_encode( - 'user=' . $this->username . "\1" . - 'auth=Bearer ' . $this->access_token . "\1\1" - ); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Search/Query.php b/lib/horde/framework/Horde/Imap/Client/Search/Query.php deleted file mode 100644 index 179f8d46544..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Search/Query.php +++ /dev/null @@ -1,918 +0,0 @@ - - * @category Horde - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Search_Query implements Serializable -{ - /** - * Serialized version. - */ - const VERSION = 3; - - /** - * Constants for dateSearch() - */ - const DATE_BEFORE = 'BEFORE'; - const DATE_ON = 'ON'; - const DATE_SINCE = 'SINCE'; - - /** - * Constants for intervalSearch() - */ - const INTERVAL_OLDER = 'OLDER'; - const INTERVAL_YOUNGER = 'YOUNGER'; - - /** - * The charset of the search strings. All text strings must be in - * this charset. By default, this is 'US-ASCII' (see RFC 3501 [6.4.4]). - * - * @var string - */ - protected $_charset = null; - - /** - * The list of search params. - * - * @var array - */ - protected $_search = array(); - - /** - * String representation: The IMAP search string. - */ - public function __toString() - { - try { - $res = $this->build(null); - return $res['query']->escape(); - } catch (Exception $e) { - return ''; - } - } - - /** - * Sets the charset of the search text. - * - * @param string $charset The charset to use for the search. - * @param boolean $convert Convert existing text values? - * - * @throws Horde_Imap_Client_Exception_SearchCharset - */ - public function charset($charset, $convert = true) - { - $oldcharset = $this->_charset; - $this->_charset = Horde_String::upper($charset); - - if (!$convert || ($oldcharset == $this->_charset)) { - return; - } - - foreach (array('and', 'or') as $item) { - if (isset($this->_search[$item])) { - foreach ($this->_search[$item] as &$val) { - $val->charset($charset, $convert); - } - } - } - - // Unset the reference to avoid corrupting $this->_search below. - unset($val); - - foreach (array('header', 'text') as $item) { - if (isset($this->_search[$item])) { - foreach ($this->_search[$item] as $key => $val) { - $new_val = Horde_String::convertCharset($val['text'], $oldcharset, $this->_charset); - if (Horde_String::convertCharset($new_val, $this->_charset, $oldcharset) != $val['text']) { - throw new Horde_Imap_Client_Exception_SearchCharset($this->_charset); - } - $this->_search[$item][$key]['text'] = $new_val; - } - } - } - } - - /** - * Builds an IMAP4rev1 compliant search string. - * - * @todo Change default of $exts to null. - * - * @param Horde_Imap_Client_Base $exts The server object this query will - * be run on (@since 2.24.0), a - * Horde_Imap_Client_Data_Capability - * object (@since 2.24.0), or the - * list of extensions present - * on the server (@deprecated). - * If null, all extensions are - * assumed to be available. - * - * @return array An array with these elements: - * - charset: (string) The charset of the search string. If null, no - * text strings appear in query. - * - exts: (array) The list of IMAP extensions used to create the - * string. - * - query: (Horde_Imap_Client_Data_Format_List) The IMAP search - * command. - * - * @throws Horde_Imap_Client_Data_Format_Exception - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - public function build($exts = array()) - { - /* @todo: BC */ - if (is_array($exts)) { - $tmp = new Horde_Imap_Client_Data_Capability_Imap(); - foreach ($exts as $key => $val) { - $tmp->add($key, is_array($val) ? $val : null); - } - $exts = $tmp; - } elseif (!is_null($exts)) { - if ($exts instanceof Horde_Imap_Client_Base) { - $exts = $exts->capability; - } elseif (!($exts instanceof Horde_Imap_Client_Data_Capability)) { - throw new InvalidArgumentException('Incorrect $exts parameter'); - } - } - - $temp = array( - 'cmds' => new Horde_Imap_Client_Data_Format_List(), - 'exts' => $exts, - 'exts_used' => array() - ); - $cmds = &$temp['cmds']; - $charset = $charset_cname = null; - $default_search = true; - $exts_used = &$temp['exts_used']; - $ptr = &$this->_search; - - $charset_get = function ($c) use (&$charset, &$charset_cname) { - $charset = is_null($c) - ? 'US-ASCII' - : strval($c); - $charset_cname = ($charset === 'US-ASCII') - ? 'Horde_Imap_Client_Data_Format_Astring' - : 'Horde_Imap_Client_Data_Format_Astring_Nonascii'; - }; - $create_return = function ($charset, $exts_used, $cmds) { - return array( - 'charset' => $charset, - 'exts' => array_keys(array_flip($exts_used)), - 'query' => $cmds - ); - }; - - /* Do IDs check first. If there is an empty ID query (without a NOT - * qualifier), the rest of this query is irrelevant since we already - * know the search will return no results. */ - if (isset($ptr['ids'])) { - if (!count($ptr['ids']['ids']) && !$ptr['ids']['ids']->special) { - if (empty($ptr['ids']['not'])) { - /* This is a match on an empty list of IDs. We do need to - * process any OR queries that may exist, since they are - * independent of this result. */ - if (isset($ptr['or'])) { - $this->_buildAndOr( - 'OR', $ptr['or'], $charset, $exts_used, $cmds - ); - } - return $create_return($charset, $exts_used, $cmds); - } - - /* If reached here, this a NOT search of an empty list. We can - * safely discard this from the output. */ - } else { - $this->_addFuzzy(!empty($ptr['ids']['fuzzy']), $temp); - if (!empty($ptr['ids']['not'])) { - $cmds->add('NOT'); - } - if (!$ptr['ids']['ids']->sequence) { - $cmds->add('UID'); - } - $cmds->add(strval($ptr['ids']['ids'])); - } - } - - if (isset($ptr['new'])) { - $this->_addFuzzy(!empty($ptr['newfuzzy']), $temp); - if ($ptr['new']) { - $cmds->add('NEW'); - unset($ptr['flag']['UNSEEN']); - } else { - $cmds->add('OLD'); - } - unset($ptr['flag']['RECENT']); - } - - if (!empty($ptr['flag'])) { - foreach ($ptr['flag'] as $key => $val) { - $this->_addFuzzy(!empty($val['fuzzy']), $temp); - - $tmp = ''; - if (empty($val['set'])) { - // This is a 'NOT' search. All system flags but \Recent - // have 'UN' equivalents. - if ($key == 'RECENT') { - $cmds->add('NOT'); - } else { - $tmp = 'UN'; - } - } - - if ($val['type'] == 'keyword') { - $cmds->add(array( - $tmp . 'KEYWORD', - $key - )); - } else { - $cmds->add($tmp . $key); - } - } - } - - if (!empty($ptr['header'])) { - /* The list of 'system' headers that have a specific search - * query. */ - $systemheaders = array( - 'BCC', 'CC', 'FROM', 'SUBJECT', 'TO' - ); - - foreach ($ptr['header'] as $val) { - $this->_addFuzzy(!empty($val['fuzzy']), $temp); - - if (!empty($val['not'])) { - $cmds->add('NOT'); - } - - if (in_array($val['header'], $systemheaders)) { - $cmds->add($val['header']); - } else { - $cmds->add(array( - 'HEADER', - new Horde_Imap_Client_Data_Format_Astring($val['header']) - )); - } - - $charset_get($this->_charset); - $cmds->add( - new $charset_cname(isset($val['text']) ? $val['text'] : '') - ); - } - } - - if (!empty($ptr['text'])) { - foreach ($ptr['text'] as $val) { - $this->_addFuzzy(!empty($val['fuzzy']), $temp); - - if (!empty($val['not'])) { - $cmds->add('NOT'); - } - - $charset_get($this->_charset); - $cmds->add(array( - $val['type'], - new $charset_cname($val['text']) - )); - } - } - - if (!empty($ptr['size'])) { - foreach ($ptr['size'] as $key => $val) { - $this->_addFuzzy(!empty($val['fuzzy']), $temp); - if (!empty($val['not'])) { - $cmds->add('NOT'); - } - $cmds->add(array( - $key, - new Horde_Imap_Client_Data_Format_Number( - empty($val['size']) ? 0 : $val['size'] - ) - )); - } - } - - if (!empty($ptr['date'])) { - foreach ($ptr['date'] as $val) { - $this->_addFuzzy(!empty($val['fuzzy']), $temp); - - if (!empty($val['not'])) { - $cmds->add('NOT'); - } - - if (empty($val['header'])) { - $cmds->add($val['range']); - } else { - $cmds->add('SENT' . $val['range']); - } - $cmds->add($val['date']); - } - } - - if (!empty($ptr['within'])) { - if (is_null($exts) || $exts->query('WITHIN')) { - $exts_used[] = 'WITHIN'; - } - - foreach ($ptr['within'] as $key => $val) { - $this->_addFuzzy(!empty($val['fuzzy']), $temp); - if (!empty($val['not'])) { - $cmds->add('NOT'); - } - - if (is_null($exts) || $exts->query('WITHIN')) { - $cmds->add(array( - $key, - new Horde_Imap_Client_Data_Format_Number($val['interval']) - )); - } else { - // This workaround is only accurate to within 1 day, due - // to limitations with the IMAP4rev1 search commands. - $cmds->add(array( - ($key == self::INTERVAL_OLDER) ? self::DATE_BEFORE : self::DATE_SINCE, - new Horde_Imap_Client_Data_Format_Date('now -' . $val['interval'] . ' seconds') - )); - } - } - } - - if (!empty($ptr['modseq'])) { - if (!is_null($exts) && !$exts->query('CONDSTORE')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('CONDSTORE'); - } - - $exts_used[] = 'CONDSTORE'; - - $this->_addFuzzy(!empty($ptr['modseq']['fuzzy']), $temp); - - if (!empty($ptr['modseq']['not'])) { - $cmds->add('NOT'); - } - $cmds->add('MODSEQ'); - if (isset($ptr['modseq']['name'])) { - $cmds->add(array( - new Horde_Imap_Client_Data_Format_String($ptr['modseq']['name']), - $ptr['modseq']['type'] - )); - } - $cmds->add(new Horde_Imap_Client_Data_Format_Number($ptr['modseq']['value'])); - } - - if (isset($ptr['prevsearch'])) { - if (!is_null($exts) && !$exts->query('SEARCHRES')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('SEARCHRES'); - } - - $exts_used[] = 'SEARCHRES'; - - $this->_addFuzzy(!empty($ptr['prevsearchfuzzy']), $temp); - - if (!$ptr['prevsearch']) { - $cmds->add('NOT'); - } - $cmds->add('$'); - } - - // Add AND'ed queries - if (!empty($ptr['and'])) { - $default_search = $this->_buildAndOr( - 'AND', $ptr['and'], $charset, $exts_used, $cmds - ); - } - - // Add OR'ed queries - if (!empty($ptr['or'])) { - $default_search = $this->_buildAndOr( - 'OR', $ptr['or'], $charset, $exts_used, $cmds - ); - } - - // Default search is 'ALL' - if ($default_search && !count($cmds)) { - $cmds->add('ALL'); - } - - return $create_return($charset, $exts_used, $cmds); - } - - /** - * Builds the AND/OR query. - * - * @param string $type 'AND' or 'OR'. - * @param array $data Query data. - * @param string &$charset Search charset. - * @param array &$exts_used IMAP extensions used. - * @param Horde_Imap_Client_Data_Format_List &$cmds Command list. - * - * @return boolean True if query might return results. - */ - protected function _buildAndOr($type, $data, &$charset, &$exts_used, - &$cmds) - { - $results = false; - - foreach ($data as $val) { - $ret = $val->build(); - - /* Empty sub-query. */ - if (!count($ret['query'])) { - switch ($type) { - case 'AND': - /* Any empty sub-query means that the query MUST return - * no results. */ - $cmds = new Horde_Imap_Client_Data_Format_List(); - $exts_used = array(); - return false; - - case 'OR': - /* Skip this query. */ - continue 2; - } - } - - $results = true; - - if (!is_null($ret['charset']) && ($ret['charset'] != 'US-ASCII')) { - if (!is_null($charset) && - ($charset != 'US-ASCII') && - ($charset != $ret['charset'])) { - throw new InvalidArgumentException( - 'AND/OR queries must all have the same charset.' - ); - } - $charset = $ret['charset']; - } - - $exts_used = array_merge($exts_used, $ret['exts']); - - switch ($type) { - case 'AND': - $cmds->add($ret['query'], true); - break; - - case 'OR': - // First OR'd query - if (count($cmds)) { - $new_cmds = new Horde_Imap_Client_Data_Format_List(); - $new_cmds->add(array( - 'OR', - $ret['query'], - $cmds - )); - $cmds = $new_cmds; - } else { - $cmds = $ret['query']; - } - break; - } - } - - return $results; - } - - /** - * Adds fuzzy modifier to search keys. - * - * @param boolean $add Add the fuzzy modifier? - * @param array $temp Temporary build data. - * - * @throws Horde_Imap_Client_Exception_NoSupport_Extension - */ - protected function _addFuzzy($add, &$temp) - { - if ($add) { - if (!$temp['exts']->query('SEARCH', 'FUZZY')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('SEARCH=FUZZY'); - } - $temp['cmds']->add('FUZZY'); - $temp['exts_used'][] = 'SEARCH=FUZZY'; - } - } - - /** - * Search for a flag/keywords. - * - * @param string $name The flag or keyword name. - * @param boolean $set If true, search for messages that have the flag - * set. If false, search for messages that do not - * have the flag set. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function flag($name, $set = true, array $opts = array()) - { - $name = Horde_String::upper(ltrim($name, '\\')); - if (!isset($this->_search['flag'])) { - $this->_search['flag'] = array(); - } - - /* The list of defined system flags (see RFC 3501 [2.3.2]). */ - $systemflags = array( - 'ANSWERED', 'DELETED', 'DRAFT', 'FLAGGED', 'RECENT', 'SEEN' - ); - - $this->_search['flag'][$name] = array_filter(array( - 'fuzzy' => !empty($opts['fuzzy']), - 'set' => $set, - 'type' => in_array($name, $systemflags) ? 'flag' : 'keyword' - )); - } - - /** - * Determines if flags are a part of the search. - * - * @return boolean True if search query involves flags. - */ - public function flagSearch() - { - return !empty($this->_search['flag']); - } - - /** - * Search for either new messages (messages that have the '\Recent' flag - * but not the '\Seen' flag) or old messages (messages that do not have - * the '\Recent' flag). If new messages are searched, this will clear - * any '\Recent' or '\Unseen' flag searches. If old messages are searched, - * this will clear any '\Recent' flag search. - * - * @param boolean $newmsgs If true, searches for new messages. Else, - * search for old messages. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function newMsgs($newmsgs = true, array $opts = array()) - { - $this->_search['new'] = $newmsgs; - if (!empty($opts['fuzzy'])) { - $this->_search['newfuzzy'] = true; - } - } - - /** - * Search for text in the header of a message. - * - * @param string $header The header field. - * @param string $text The search text. - * @param boolean $not If true, do a 'NOT' search of $text. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function headerText($header, $text, $not = false, - array $opts = array()) - { - if (!isset($this->_search['header'])) { - $this->_search['header'] = array(); - } - $this->_search['header'][] = array_filter(array( - 'fuzzy' => !empty($opts['fuzzy']), - 'header' => Horde_String::upper($header), - 'text' => $text, - 'not' => $not - )); - } - - /** - * Search for text in either the entire message, or just the body. - * - * @param string $text The search text. - * @param boolean $bodyonly If true, only search in the body of the - * message. If false, also search in the headers. - * @param boolean $not If true, do a 'NOT' search of $text. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function text($text, $bodyonly = true, $not = false, - array $opts = array()) - { - if (!isset($this->_search['text'])) { - $this->_search['text'] = array(); - } - - $this->_search['text'][] = array_filter(array( - 'fuzzy' => !empty($opts['fuzzy']), - 'not' => $not, - 'text' => $text, - 'type' => $bodyonly ? 'BODY' : 'TEXT' - )); - } - - /** - * Search for messages smaller/larger than a certain size. - * - * @todo: Remove $not for 3.0 - * - * @param integer $size The size (in bytes). - * @param boolean $larger Search for messages larger than $size? - * @param boolean $not If true, do a 'NOT' search of $text. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function size($size, $larger = false, $not = false, - array $opts = array()) - { - if (!isset($this->_search['size'])) { - $this->_search['size'] = array(); - } - $this->_search['size'][$larger ? 'LARGER' : 'SMALLER'] = array_filter(array( - 'fuzzy' => !empty($opts['fuzzy']), - 'not' => $not, - 'size' => (float)$size - )); - } - - /** - * Search for messages within a given UID range. Only one message range - * can be specified per query. - * - * @param Horde_Imap_Client_Ids $ids The list of UIDs to search. - * @param boolean $not If true, do a 'NOT' search of the - * UIDs. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function ids(Horde_Imap_Client_Ids $ids, $not = false, - array $opts = array()) - { - $this->_search['ids'] = array_filter(array( - 'fuzzy' => !empty($opts['fuzzy']), - 'ids' => $ids, - 'not' => $not - )); - } - - /** - * Search for messages within a date range. - * - * @param mixed $date DateTime or Horde_Date object. - * @param string $range Either: - * - Horde_Imap_Client_Search_Query::DATE_BEFORE - * - Horde_Imap_Client_Search_Query::DATE_ON - * - Horde_Imap_Client_Search_Query::DATE_SINCE - * @param boolean $header If true, search using the date in the message - * headers. If false, search using the internal - * IMAP date (usually arrival time). - * @param boolean $not If true, do a 'NOT' search of the range. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function dateSearch($date, $range, $header = true, $not = false, - array $opts = array()) - { - if (!isset($this->_search['date'])) { - $this->_search['date'] = array(); - } - - // We should really be storing the raw DateTime object as data, - // but all versions of the query object have converted at this stage. - $ob = new Horde_Imap_Client_Data_Format_Date($date); - - $this->_search['date'][] = array_filter(array( - 'date' => $ob->escape(), - 'fuzzy' => !empty($opts['fuzzy']), - 'header' => $header, - 'range' => $range, - 'not' => $not - )); - } - - /** - * Search for messages within a date and time range. - * - * @param mixed $date DateTime or Horde_Date object. - * @param string $range Either: - * - Horde_Imap_Client_Search_Query::DATE_BEFORE - * - Horde_Imap_Client_Search_Query::DATE_ON - * - Horde_Imap_Client_Search_Query::DATE_SINCE - * @param boolean $header If true, search using the date in the message - * headers. If false, search using the internal - * IMAP date (usually arrival time). - * @param boolean $not If true, do a 'NOT' search of the range. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function dateTimeSearch($date, $range, $header = true, $not = false, - array $opts = array()) - { - if (!isset($this->_search['date'])) { - $this->_search['date'] = array(); - } - - // We should really be storing the raw DateTime object as data, - // but all versions of the query object have converted at this stage. - $ob = new Horde_Imap_Client_Data_Format_DateTime($date); - - $this->_search['date'][] = array_filter(array( - 'date' => $ob->escape(), - 'fuzzy' => !empty($opts['fuzzy']), - 'header' => $header, - 'range' => $range, - 'not' => $not - )); - } - - /** - * Search for messages within a given interval. Only one interval of each - * type can be specified per search query. If the IMAP server supports - * the WITHIN extension (RFC 5032), it will be used. Otherwise, the - * search query will be dynamically created using IMAP4rev1 search - * terms. - * - * @param integer $interval Seconds from the present. - * @param string $range Either: - * - Horde_Imap_Client_Search_Query::INTERVAL_OLDER - * - Horde_Imap_Client_Search_Query::INTERVAL_YOUNGER - * @param boolean $not If true, do a 'NOT' search. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function intervalSearch($interval, $range, $not = false, - array $opts = array()) - { - if (!isset($this->_search['within'])) { - $this->_search['within'] = array(); - } - $this->_search['within'][$range] = array( - 'fuzzy' => !empty($opts['fuzzy']), - 'interval' => $interval, - 'not' => $not - ); - } - - /** - * AND queries - the contents of this query will be AND'ed (in its - * entirety) with the contents of EACH of the queries passed in. All - * AND'd queries must share the same charset as this query. - * - * @param mixed $queries A query, or an array of queries, to AND with the - * current query. - */ - public function andSearch($queries) - { - if (!isset($this->_search['and'])) { - $this->_search['and'] = array(); - } - - if ($queries instanceof Horde_Imap_Client_Search_Query) { - $queries = array($queries); - } - - $this->_search['and'] = array_merge($this->_search['and'], $queries); - } - - /** - * OR a query - the contents of this query will be OR'ed (in its entirety) - * with the contents of EACH of the queries passed in. All OR'd queries - * must share the same charset as this query. All contents of any single - * query will be AND'ed together. - * - * @param mixed $queries A query, or an array of queries, to OR with the - * current query. - */ - public function orSearch($queries) - { - if (!isset($this->_search['or'])) { - $this->_search['or'] = array(); - } - - if ($queries instanceof Horde_Imap_Client_Search_Query) { - $queries = array($queries); - } - - $this->_search['or'] = array_merge($this->_search['or'], $queries); - } - - /** - * Search for messages modified since a specific moment. The IMAP server - * must support the CONDSTORE extension (RFC 7162) for this query to be - * used. - * - * @param integer $value The mod-sequence value. - * @param string $name The entry-name string. - * @param string $type Either 'shared', 'priv', or 'all'. Defaults to - * 'all' - * @param boolean $not If true, do a 'NOT' search. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function modseq($value, $name = null, $type = null, $not = false, - array $opts = array()) - { - if (!is_null($type)) { - $type = Horde_String::lower($type); - if (!in_array($type, array('shared', 'priv', 'all'))) { - $type = 'all'; - } - } - - $this->_search['modseq'] = array_filter(array( - 'fuzzy' => !empty($opts['fuzzy']), - 'name' => $name, - 'not' => $not, - 'type' => (!is_null($name) && is_null($type)) ? 'all' : $type, - 'value' => $value - )); - } - - /** - * Use the results from the previous SEARCH command. The IMAP server must - * support the SEARCHRES extension (RFC 5182) for this query to be used. - * - * @param boolean $not If true, don't match the previous query. - * @param array $opts Additional options: - * - fuzzy: (boolean) If true, perform a fuzzy search. The IMAP server - * MUST support RFC 6203. - */ - public function previousSearch($not = false, array $opts = array()) - { - $this->_search['prevsearch'] = $not; - if (!empty($opts['fuzzy'])) { - $this->_search['prevsearchfuzzy'] = true; - } - } - - /* Serializable methods. */ - - public function serialize() - { - return serialize($this->__serialize()); - } - - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version change.'); - } - - $this->__unserialize($data); - } - - /** - * Serialization. - * - * @return string Serialized data. - */ - public function __serialize() - { - $data = array( - // Serialized data ID. - self::VERSION, - $this->_search - ); - - if (!is_null($this->_charset)) { - $data[] = $this->_charset; - } - - return $data; - } - - /** - * Unserialization. - * - * @param string $data Serialized data. - * - * @throws Exception - */ - public function __unserialize($data) - { - if (!is_array($data) || - !isset($data[0]) || - ($data[0] != self::VERSION)) { - throw new Exception('Cache version change'); - } - - $this->_search = $data[1]; - if (isset($data[2])) { - $this->_charset = $data[2]; - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Socket.php b/lib/horde/framework/Horde/Imap/Client/Socket.php deleted file mode 100644 index 9fddb7d9a06..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Socket.php +++ /dev/null @@ -1,5166 +0,0 @@ - - * - RFC 2086/4314: ACL - * - RFC 2087: QUOTA - * - RFC 2088: LITERAL+ - * - RFC 2195: AUTH=CRAM-MD5 - * - RFC 2221: LOGIN-REFERRALS - * - RFC 2342: NAMESPACE - * - RFC 2595/4616: TLS & AUTH=PLAIN - * - RFC 2831: DIGEST-MD5 authentication mechanism (obsoleted by RFC 6331) - * - RFC 2971: ID - * - RFC 3348: CHILDREN - * - RFC 3501: IMAP4rev1 specification - * - RFC 3502: MULTIAPPEND - * - RFC 3516: BINARY - * - RFC 3691: UNSELECT - * - RFC 4315: UIDPLUS - * - RFC 4422: SASL Authentication (for DIGEST-MD5) - * - RFC 4466: Collected extensions (updates RFCs 2088, 3501, 3502, 3516) - * - RFC 4469/5550: CATENATE - * - RFC 4731: ESEARCH - * - RFC 4959: SASL-IR - * - RFC 5032: WITHIN - * - RFC 5161: ENABLE - * - RFC 5182: SEARCHRES - * - RFC 5255: LANGUAGE/I18NLEVEL - * - RFC 5256: THREAD/SORT - * - RFC 5258: LIST-EXTENDED - * - RFC 5267: ESORT; PARTIAL search return option - * - RFC 5464: METADATA - * - RFC 5530: IMAP Response Codes - * - RFC 5802: AUTH=SCRAM-SHA-1 - * - RFC 5819: LIST-STATUS - * - RFC 5957: SORT=DISPLAY - * - RFC 6154: SPECIAL-USE/CREATE-SPECIAL-USE - * - RFC 6203: SEARCH=FUZZY - * - RFC 6851: MOVE - * - RFC 6855: UTF8=ACCEPT/UTF8=ONLY - * - RFC 6858: DOWNGRADED response code - * - RFC 7162: CONDSTORE/QRESYNC - *
- * - * Implements the following non-RFC extensions: - *
- *   - draft-ietf-morg-inthread-01: THREAD=REFS
- *   - draft-daboo-imap-annotatemore-07: ANNOTATEMORE
- *   - draft-daboo-imap-annotatemore-08: ANNOTATEMORE2
- *   - XIMAPPROXY
- *     Requires imapproxy v1.2.7-rc1 or later
- *     See https://squirrelmail.svn.sourceforge.net/svnroot/squirrelmail/trunk/imap_proxy/README
- *   - AUTH=XOAUTH2
- *     https://developers.google.com/gmail/xoauth2_protocol
- * 
- * - * TODO (or not necessary?): - *
- *   - RFC 2177: IDLE
- *   - RFC 2193: MAILBOX-REFERRALS
- *   - RFC 4467/5092/5524/5550/5593: URLAUTH, URLAUTH=BINARY, URL-PARTIAL
- *   - RFC 4978: COMPRESS=DEFLATE
- *     See: http://bugs.php.net/bug.php?id=48725
- *   - RFC 5257: ANNOTATE (Experimental)
- *   - RFC 5259: CONVERT
- *   - RFC 5267: CONTEXT=SEARCH; CONTEXT=SORT
- *   - RFC 5465: NOTIFY
- *   - RFC 5466: FILTERS
- *   - RFC 6785: IMAPSIEVE
- *   - RFC 7377: MULTISEARCH
- * 
- * - * @author Michael Slusarz - * @category Horde - * @copyright 1999-2007 The SquirrelMail Project Team - * @copyright 2005-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Socket extends Horde_Imap_Client_Base -{ - /** - * Cache names used exclusively within this class. - */ - const CACHE_FLAGS = 'HICflags'; - - /** - * Queued commands to send to the server. - * - * @var array - */ - protected $_cmdQueue = array(); - - /** - * The default ports to use for a connection. - * - * @var array - */ - protected $_defaultPorts = array(143, 993); - - /** - * Mapping of status fields to IMAP names. - * - * @var array - */ - protected $_statusFields = array( - 'messages' => Horde_Imap_Client::STATUS_MESSAGES, - 'recent' => Horde_Imap_Client::STATUS_RECENT, - 'uidnext' => Horde_Imap_Client::STATUS_UIDNEXT, - 'uidvalidity' => Horde_Imap_Client::STATUS_UIDVALIDITY, - 'unseen' => Horde_Imap_Client::STATUS_UNSEEN, - 'firstunseen' => Horde_Imap_Client::STATUS_FIRSTUNSEEN, - 'flags' => Horde_Imap_Client::STATUS_FLAGS, - 'permflags' => Horde_Imap_Client::STATUS_PERMFLAGS, - 'uidnotsticky' => Horde_Imap_Client::STATUS_UIDNOTSTICKY, - 'highestmodseq' => Horde_Imap_Client::STATUS_HIGHESTMODSEQ - ); - - /** - * The unique tag to use when making an IMAP query. - * - * @var integer - */ - protected $_tag = 0; - - /** - * @param array $params A hash containing configuration parameters. - * Additional parameters to base driver: - * - debug_literal: (boolean) If true, will output the raw text of - * literal responses to the debug stream. Otherwise, - * outputs a summary of the literal response. - * - envelope_addrs: (integer) The maximum number of address entries to - * read for FETCH ENVELOPE address fields. - * DEFAULT: 1000 - * - envelope_string: (integer) The maximum length of string fields - * returned by the FETCH ENVELOPE command. - * DEFAULT: 2048 - * - xoauth2_token: (mixed) If set, will authenticate via the XOAUTH2 - * mechanism (if available) with this token. Either a - * string (since 2.13.0) or a - * Horde_Imap_Client_Base_Password object (since - * 2.14.0). - */ - public function __construct(array $params = array()) - { - parent::__construct(array_merge(array( - 'debug_literal' => false, - 'envelope_addrs' => 1000, - 'envelope_string' => 2048 - ), $params)); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'search_charset': - if (!isset($this->_init['search_charset']) && - $this->_capability()->isEnabled('UTF8=ACCEPT')) { - $this->_init['search_charset'] = new Horde_Imap_Client_Data_SearchCharset_Utf8(); - } - break; - } - - return parent::__get($name); - } - - /** - */ - public function getParam($key) - { - switch ($key) { - case 'xoauth2_token': - if (isset($this->_params[$key]) && - ($this->_params[$key] instanceof Horde_Imap_Client_Base_Password)) { - return $this->_params[$key]->getPassword(); - } - break; - } - - return parent::getParam($key); - } - - /** - */ - public function update(SplSubject $subject) - { - if (!empty($this->_init['imapproxy']) && - ($subject instanceof Horde_Imap_Client_Data_Capability_Imap)) { - $this->_setInit('enabled', $subject->isEnabled()); - } - - return parent::update($subject); - } - - /** - */ - protected function _initCapability() - { - // Need to use connect call here or else we run into loop issues - // because _connect() can generate the capability object internally. - $this->_connect(); - - // It is possible the server provided capability information on - // connect, so check for it now. - if (!isset($this->_init['capability'])) { - $this->_sendCmd($this->_command('CAPABILITY')); - } - } - - /** - * Parse a CAPABILITY Response (RFC 3501 [7.2.1]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param array $data An array of CAPABILITY strings. - */ - protected function _parseCapability( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - $data - ) - { - if (!empty($this->_temp['no_cap'])) { - return; - } - - $pipeline->data['capability_set'] = true; - - $c = new Horde_Imap_Client_Data_Capability_Imap(); - - foreach ($data as $val) { - $cap_list = explode('=', $val); - $c->add( - $cap_list[0], - isset($cap_list[1]) ? array($cap_list[1]) : null - ); - } - - $this->_setInit('capability', $c); - } - - /** - */ - protected function _noop() - { - // NOOP doesn't return any specific response - $this->_sendCmd($this->_command('NOOP')); - } - - /** - */ - protected function _getNamespaces() - { - if ($this->_capability('NAMESPACE')) { - $data = $this->_sendCmd($this->_command('NAMESPACE'))->data; - if (isset($data['namespace'])) { - return $data['namespace']; - } - } - - return new Horde_Imap_Client_Namespace_List(); - } - - /** - * Parse a NAMESPACE response (RFC 2342 [5] & RFC 5255 [3.4]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The NAMESPACE data. - */ - protected function _parseNamespace( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - $namespace_array = array( - Horde_Imap_Client_Data_Namespace::NS_PERSONAL, - Horde_Imap_Client_Data_Namespace::NS_OTHER, - Horde_Imap_Client_Data_Namespace::NS_SHARED - ); - - $c = array(); - - // Per RFC 2342, response from NAMESPACE command is: - // (PERSONAL NAMESPACES) (OTHER_USERS NAMESPACE) (SHARED NAMESPACES) - foreach ($namespace_array as $val) { - $entry = $data->next(); - - if (is_null($entry)) { - continue; - } - - while ($data->next() !== false) { - $ob = Horde_Imap_Client_Mailbox::get($data->next(), true); - - $ns = new Horde_Imap_Client_Data_Namespace(); - $ns->delimiter = $data->next(); - $ns->name = strval($ob); - $ns->type = $val; - $c[strval($ob)] = $ns; - - // RFC 4466: NAMESPACE extensions - while (($ext = $data->next()) !== false) { - switch (Horde_String::upper($ext)) { - case 'TRANSLATION': - // RFC 5255 [3.4] - TRANSLATION extension - $data->next(); - $ns->translation = $data->next(); - $data->next(); - break; - } - } - } - } - - $pipeline->data['namespace'] = new Horde_Imap_Client_Namespace_List($c); - } - - /** - */ - protected function _login() - { - $secure = $this->getParam('secure'); - - if (!empty($this->_temp['preauth'])) { - unset($this->_temp['preauth']); - - /* Don't allow PREAUTH if we are requring secure access, since - * PREAUTH cannot provide secure access. */ - if (!$this->isSecureConnection() && ($secure !== false)) { - $this->logout(); - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Could not open secure TLS connection to the IMAP server."), - Horde_Imap_Client_Exception::LOGIN_TLSFAILURE - ); - } - - return $this->_loginTasks(); - } - - /* Blank passwords are not allowed, so no need to even try - * authentication to determine this. */ - if (!strlen($this->getParam('password'))) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("No password provided."), - Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED - ); - } - - $this->_connect(); - - $first_login = empty($this->_init['authmethod']); - - // Switch to secure channel if using TLS. - if (!$this->isSecureConnection() && - (($secure === 'tls') || - (($secure === true) && - $this->_capability('LOGINDISABLED')))) { - if ($first_login && !$this->_capability('STARTTLS')) { - /* We should never hit this - STARTTLS is required pursuant to - * RFC 3501 [6.2.1]. */ - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Server does not support TLS connections."), - Horde_Imap_Client_Exception::LOGIN_TLSFAILURE - ); - } - - // Switch over to a TLS connection. - // STARTTLS returns no untagged response. - $this->_sendCmd($this->_command('STARTTLS')); - - if (!$this->_connection->startTls()) { - $this->logout(); - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Could not open secure TLS connection to the IMAP server."), - Horde_Imap_Client_Exception::LOGIN_TLSFAILURE - ); - } - - $this->_debug->info('Successfully completed TLS negotiation.'); - - $this->setParam('secure', 'tls'); - $secure = 'tls'; - - if ($first_login) { - // Expire cached CAPABILITY information (RFC 3501 [6.2.1]) - $this->_setInit('capability'); - - // Reset language (RFC 5255 [3.1]) - $this->_setInit('lang'); - } - - // Set language if using imapproxy - if (!empty($this->_init['imapproxy'])) { - $this->setLanguage(); - } - } - - /* If we reached this point and don't have a secure connection, then - * a secure connections is not available. */ - if (($secure === true) && !$this->isSecureConnection()) { - $this->setParam('secure', false); - $secure = false; - } - - if ($first_login) { - // Add authentication methods. - $auth_mech = array(); - $auth = array_flip($this->_capability()->getParams('AUTH')); - - // XOAUTH2 - if (isset($auth['XOAUTH2']) && $this->getParam('xoauth2_token')) { - $auth_mech[] = 'XOAUTH2'; - } - unset($auth['XOAUTH2']); - - /* 'AUTH=PLAIN' authentication always exists if under TLS (RFC 3501 - * [7.2.1]; RFC 2595), even though we might get here with a - * non-TLS secure connection too. Use it over all other - * authentication methods, although we need to do sanity checking - * since broken IMAP servers may not support as required - - * fallback to LOGIN instead, if not explicitly disabled. */ - if ($secure) { - if (isset($auth['PLAIN'])) { - $auth_mech[] = 'PLAIN'; - unset($auth['PLAIN']); - } elseif (!$this->_capability('LOGINDISABLED')) { - $auth_mech[] = 'LOGIN'; - } - } - - // Check for supported SCRAM AUTH mechanisms. Preferred because it - // provides verification of server authenticity. - foreach (array_keys($auth) as $key) { - switch ($key) { - case 'SCRAM-SHA-1': - $auth_mech[] = $key; - unset($auth[$key]); - break; - } - } - - // Check for supported CRAM AUTH mechanisms. - foreach (array_keys($auth) as $key) { - switch ($key) { - case 'CRAM-SHA1': - case 'CRAM-SHA256': - $auth_mech[] = $key; - unset($auth[$key]); - break; - } - } - - // Prefer CRAM-MD5 over DIGEST-MD5, as the latter has been - // obsoleted (RFC 6331). - if (isset($auth['CRAM-MD5'])) { - $auth_mech[] = 'CRAM-MD5'; - } elseif (isset($auth['DIGEST-MD5'])) { - $auth_mech[] = 'DIGEST-MD5'; - } - unset($auth['CRAM-MD5'], $auth['DIGEST-MD5']); - - // Add other auth mechanisms. - $auth_mech = array_merge($auth_mech, array_keys($auth)); - - // Fall back to 'LOGIN' if available. - if (!$secure && !$this->_capability('LOGINDISABLED')) { - $auth_mech[] = 'LOGIN'; - } - - if (empty($auth_mech)) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("No supported IMAP authentication method could be found."), - Horde_Imap_Client_Exception::LOGIN_NOAUTHMETHOD - ); - } - - $auth_mech = array_unique($auth_mech); - } else { - $auth_mech = array($this->_init['authmethod']); - } - - $login_err = null; - - foreach ($auth_mech as $method) { - try { - $resp = $this->_tryLogin($method); - $data = $resp->data; - $this->_setInit('authmethod', $method); - unset($this->_temp['referralcount']); - } catch (Horde_Imap_Client_Exception_ServerResponse $e) { - $data = $e->resp_data; - if (isset($data['loginerr'])) { - $login_err = $data['loginerr']; - } - $resp = false; - } catch (Horde_Imap_Client_Exception $e) { - $resp = false; - } - - // Check for login referral (RFC 2221) response - can happen for - // an OK, NO, or BYE response. - if (isset($data['referral'])) { - foreach (array('host', 'port', 'username') as $val) { - if (!is_null($data['referral']->$val)) { - $this->setParam($val, $data['referral']->$val); - } - } - - if (!is_null($data['referral']->auth)) { - $this->_setInit('authmethod', $data['referral']->auth); - } - - if (!isset($this->_temp['referralcount'])) { - $this->_temp['referralcount'] = 0; - } - - // RFC 2221 [3] - Don't follow more than 10 levels of referral - // without consulting the user. - if (++$this->_temp['referralcount'] < 10) { - $this->logout(); - $this->_setInit('capability'); - $this->_setInit('namespace'); - return $this->login(); - } - - unset($this->_temp['referralcount']); - } - - if ($resp) { - return $this->_loginTasks($first_login, $resp->data); - } - } - - /* Try again from scratch if authentication failed in an established, - * previously-authenticated object. */ - if (!empty($this->_init['authmethod'])) { - $this->_setInit(); - unset($this->_temp['no_cap']); - try { - return $this->_login(); - } catch (Horde_Imap_Client_Exception $e) {} - } - - /* Default to AUTHENTICATIONFAILED error (see RFC 5530[3]). */ - if (is_null($login_err)) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Mail server denied authentication."), - Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED - ); - } - - throw $login_err; - } - - /** - * Connects to the IMAP server. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _connect() - { - if (!is_null($this->_connection)) { - return; - } - - try { - $this->_connection = new Horde_Imap_Client_Socket_Connection_Socket( - $this->getParam('hostspec'), - $this->getParam('port'), - $this->getParam('timeout'), - $this->getParam('secure'), - $this->getParam('context'), - array( - 'debug' => $this->_debug, - 'debugliteral' => $this->getParam('debug_literal') - ) - ); - } catch (Horde\Socket\Client\Exception $e) { - $e2 = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error connecting to mail server."), - Horde_Imap_Client_Exception::SERVER_CONNECT - ); - $e2->details = $e->details; - throw $e2; - } - - // If we already have capability information, don't re-set with - // (possibly) limited information sent in the initial banner. - if (isset($this->_init['capability'])) { - $this->_temp['no_cap'] = true; - } - - /* Get greeting information (untagged response). */ - try { - $this->_getLine($this->_pipeline()); - } catch (Horde_Imap_Client_Exception_ServerResponse $e) { - if ($e->status === Horde_Imap_Client_Interaction_Server::BYE) { - /* Server is explicitly rejecting our connection (RFC 3501 - * [7.1.5]). */ - $e->setMessage(Horde_Imap_Client_Translation::r("Server rejected connection.")); - $e->setCode(Horde_Imap_Client_Exception::SERVER_CONNECT); - } - throw $e; - } - - // Check for IMAP4rev1 support - if (!$this->_capability('IMAP4REV1')) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("The mail server does not support IMAP4rev1 (RFC 3501)."), - Horde_Imap_Client_Exception::SERVER_CONNECT - ); - } - - // Set language if NOT using imapproxy - if (empty($this->_init['imapproxy'])) { - if ($this->_capability('XIMAPPROXY')) { - $this->_setInit('imapproxy', true); - } else { - $this->setLanguage(); - } - } - - // If pre-authenticated, we need to do all login tasks now. - if (!empty($this->_temp['preauth'])) { - $this->login(); - } - } - - /** - * Authenticate to the IMAP server. - * - * @param string $method IMAP login method. - * - * @return Horde_Imap_Client_Interaction_Pipeline Pipeline object. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _tryLogin($method) - { - $username = $this->getParam('username'); - if (is_null($authusername = $this->getParam('authusername'))) { - $authusername = $username; - } - $password = $this->getParam('password'); - - switch ($method) { - case 'CRAM-MD5': - case 'CRAM-SHA1': - case 'CRAM-SHA256': - // RFC 2195: CRAM-MD5 - // CRAM-SHA1 & CRAM-SHA256 supported by Courier SASL library - - $args = array( - $username, - Horde_String::lower(substr($method, 5)), - $password - ); - - $cmd = $this->_command('AUTHENTICATE')->add(array( - $method, - new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) use ($args) { - return new Horde_Imap_Client_Data_Format_List( - base64_encode($args[0] . ' ' . hash_hmac($args[1], base64_decode($ob->token->current()), $args[2], false)) - ); - }) - )); - $cmd->debug = array( - null, - sprintf('[AUTHENTICATE response (username: %s)]', $username) - ); - break; - - case 'DIGEST-MD5': - // RFC 2831/4422; obsoleted by RFC 6331 - - // Need $args because PHP 5.3 doesn't allow access to $this in - // anonymous functions. - $args = array( - $username, - $password, - $this->getParam('hostspec') - ); - - $cmd = $this->_command('AUTHENTICATE')->add(array( - $method, - new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) use ($args) { - return new Horde_Imap_Client_Data_Format_List( - base64_encode(new Horde_Imap_Client_Auth_DigestMD5( - $args[0], - $args[1], - base64_decode($ob->token->current()), - $args[2], - 'imap' - )) - ); - }), - new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) { - if (strpos(base64_decode($ob->token->current()), 'rspauth=') === false) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Unexpected response from server when authenticating."), - Horde_Imap_Client_Exception::SERVER_CONNECT - ); - } - - return new Horde_Imap_Client_Data_Format_List(); - }) - )); - $cmd->debug = array( - null, - sprintf('[AUTHENTICATE Response (username: %s)]', $username), - null - ); - break; - - case 'LOGIN': - /* See, e.g., RFC 6855 [5] - LOGIN command does not support - * non-ASCII characters. If we reach this point, treat as an - * authentication failure. */ - try { - $username = new Horde_Imap_Client_Data_Format_Astring($username); - $password = new Horde_Imap_Client_Data_Format_Astring($password); - } catch (Horde_Imap_Client_Data_Format_Exception $e) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Authentication failed."), - Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED - ); - } - - $cmd = $this->_command('LOGIN')->add(array( - $username, - $password - )); - $cmd->debug = array( - sprintf('LOGIN %s [PASSWORD]', $username) - ); - break; - - case 'PLAIN': - // RFC 2595/4616 - PLAIN SASL mechanism - $cmd = $this->_authInitialResponse( - $method, - base64_encode(implode("\0", array( - $username, - $authusername, - $password - ))), - $username - ); - break; - - case 'SCRAM-SHA-1': - $scram = new Horde_Imap_Client_Auth_Scram( - $username, - $password, - 'SHA1' - ); - - $cmd = $this->_authInitialResponse( - $method, - base64_encode($scram->getClientFirstMessage()) - ); - - $cmd->add( - new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) use ($scram) { - $sr1 = base64_decode($ob->token->current()); - return new Horde_Imap_Client_Data_Format_List( - $scram->parseServerFirstMessage($sr1) - ? base64_encode($scram->getClientFinalMessage()) - : '*' - ); - }) - ); - - $self = $this; - $cmd->add( - new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) use ($scram, $self) { - $sr2 = base64_decode($ob->token->current()); - if (!$scram->parseServerFinalMessage($sr2)) { - /* This means authentication passed, according to the - * server, but the server signature is incorrect. - * This indicates that server verification has failed. - * Immediately disconnect from the server, since this - * is a possible security issue. */ - $self->logout(); - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Server failed verification check."), - Horde_Imap_Client_Exception::LOGIN_SERVER_VERIFICATION_FAILED - ); - } - - return new Horde_Imap_Client_Data_Format_List(); - }) - ); - break; - - case 'XOAUTH2': - // Google XOAUTH2 - $cmd = $this->_authInitialResponse( - $method, - $this->getParam('xoauth2_token') - ); - - /* This is an optional command continuation. XOAUTH2 will return - * error information in continuation response. */ - $error_continuation = new Horde_Imap_Client_Interaction_Command_Continuation( - function($ob) { - return new Horde_Imap_Client_Data_Format_List(); - } - ); - $error_continuation->optional = true; - $cmd->add($error_continuation); - break; - - default: - $e = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Unknown authentication method: %s"), - Horde_Imap_Client_Exception::SERVER_CONNECT - ); - $e->messagePrintf(array($method)); - throw $e; - } - - return $this->_sendCmd($this->_pipeline($cmd)); - } - - /** - * Create the AUTHENTICATE command for the initial client response. - * - * @param string $method AUTHENTICATE SASL method. - * @param string $ir Initial client response. - * @param string $username If set, log a username message in debug log - * instead of raw data. - * - * @return Horde_Imap_Client_Interaction_Command A command object. - */ - protected function _authInitialResponse($method, $ir, $username = null) - { - $cmd = $this->_command('AUTHENTICATE')->add($method); - - if ($this->_capability('SASL-IR')) { - // IMAP Extension for SASL Initial Client Response (RFC 4959) - $cmd->add($ir); - if ($username) { - $cmd->debug = array( - sprintf('AUTHENTICATE %s [INITIAL CLIENT RESPONSE (username: %s)]', $method, $username) - ); - } - } else { - $cmd->add( - new Horde_Imap_Client_Interaction_Command_Continuation(function($ob) use ($ir) { - return new Horde_Imap_Client_Data_Format_List($ir); - }) - ); - if ($username) { - $cmd->debug = array( - null, - sprintf('[INITIAL CLIENT RESPONSE (username: %s)]', $username) - ); - } - } - - return $cmd; - } - - /** - * Perform login tasks. - * - * @param boolean $firstlogin Is this the first login? - * @param array $resp The data response from the login command. - * May include: - * - capability_set: (boolean) True if CAPABILITY was set after login. - * - proxyreuse: (boolean) True if re-used connection via imapproxy. - * - * @return boolean True if global login tasks should be performed. - */ - protected function _loginTasks($firstlogin = true, array $resp = array()) - { - /* If reusing an imapproxy connection, no need to do any of these - * login tasks again. */ - if (!$firstlogin && !empty($resp['proxyreuse'])) { - if (isset($this->_init['enabled'])) { - foreach ($this->_init['enabled'] as $val) { - $this->_capability()->enable($val); - } - } - - // If we have not yet set the language, set it now. - if (!isset($this->_init['lang'])) { - $this->_temp['lang_queue'] = true; - $this->setLanguage(); - unset($this->_temp['lang_queue']); - } - return false; - } - - /* If we logged in for first time, and server did not return - * capability information, we need to mark for retrieval. */ - if ($firstlogin && empty($resp['capability_set'])) { - $this->_setInit('capability'); - } - - $this->_temp['lang_queue'] = true; - $this->setLanguage(); - unset($this->_temp['lang_queue']); - - /* Only active QRESYNC/CONDSTORE if caching is enabled. */ - $enable = array(); - if ($this->_initCache()) { - if ($this->_capability('QRESYNC')) { - $enable[] = 'QRESYNC'; - } elseif ($this->_capability('CONDSTORE')) { - $enable[] = 'CONDSTORE'; - } - } - - /* Use UTF8=ACCEPT, if available. */ - if ($this->_capability('UTF8', 'ACCEPT')) { - $enable[] = 'UTF8=ACCEPT'; - } - - $this->_enable($enable); - - return true; - } - - /** - */ - protected function _logout() - { - if (empty($this->_temp['logout'])) { - /* If using imapproxy, force sending these commands, since they - * may not be sent again if they are (likely) initialization - * commands. */ - if (!empty($this->_cmdQueue) && - !empty($this->_init['imapproxy'])) { - $this->_sendCmd($this->_pipeline()); - } - - $this->_temp['logout'] = true; - try { - $this->_sendCmd($this->_command('LOGOUT')); - } catch (Horde_Imap_Client_Exception_ServerResponse $e) { - // Ignore server errors - } - unset($this->_temp['logout']); - } - } - - /** - */ - protected function _sendID($info) - { - $cmd = $this->_command('ID'); - - if (empty($info)) { - $cmd->add(new Horde_Imap_Client_Data_Format_Nil()); - } else { - $tmp = new Horde_Imap_Client_Data_Format_List(); - foreach ($info as $key => $val) { - $tmp->add(array( - new Horde_Imap_Client_Data_Format_String(Horde_String::lower($key)), - new Horde_Imap_Client_Data_Format_Nstring($val) - )); - } - $cmd->add($tmp); - } - - $temp = &$this->_temp; - - /* Add to queue - this doesn't need to be sent immediately. */ - $cmd->on_error = function() use (&$temp) { - /* Ignore server errors. E.g. Cyrus returns this: - * 001 NO Only one Id allowed in non-authenticated state - * even though NO is not allowed in RFC 2971[3.1]. */ - $temp['id'] = array(); - return true; - }; - $cmd->on_success = function() use ($cmd, &$temp) { - $temp['id'] = $cmd->pipeline->data['id']; - }; - $this->_cmdQueue[] = $cmd; - } - - /** - * Parse an ID response (RFC 2971 [3.2]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The server response. - */ - protected function _parseID( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - if (!isset($pipeline->data['id'])) { - $pipeline->data['id'] = array(); - } - - if (!is_null($data->next())) { - while (($curr = $data->next()) !== false) { - if (!is_null($id = $data->next())) { - $pipeline->data['id'][$curr] = $id; - } - } - } - } - - /** - */ - protected function _getID() - { - if (!isset($this->_temp['id'])) { - $this->sendID(); - /* ID is queued - force sending the queued command. */ - $this->_sendCmd($this->_pipeline()); - } - - return $this->_temp['id']; - } - - /** - */ - protected function _setLanguage($langs) - { - $cmd = $this->_command('LANGUAGE'); - foreach ($langs as $lang) { - $cmd->add(new Horde_Imap_Client_Data_Format_Astring($lang)); - } - - if (!empty($this->_temp['lang_queue'])) { - $this->_cmdQueue[] = $cmd; - return array(); - } - - try { - $this->_sendCmd($cmd); - } catch (Horde_Imap_Client_Exception $e) { - $this->_setInit('lang', false); - return null; - } - - return $this->_init['lang']; - } - - /** - */ - protected function _getLanguage($list) - { - if (!$list) { - return empty($this->_init['lang']) - ? null - : $this->_init['lang']; - } - - if (!isset($this->_init['langavail'])) { - try { - $this->_sendCmd($this->_command('LANGUAGE')); - } catch (Horde_Imap_Client_Exception $e) { - $this->_setInit('langavail', array()); - } - } - - return $this->_init['langavail']; - } - - /** - * Parse a LANGUAGE response (RFC 5255 [3.3]). - * - * @param Horde_Imap_Client_Tokenize $data The server response. - */ - protected function _parseLanguage(Horde_Imap_Client_Tokenize $data) - { - $lang_list = $data->flushIterator(); - - if (count($lang_list) === 1) { - // This is the language that was set. - $this->_setInit('lang', reset($lang_list)); - } else { - // These are the languages that are available. - $this->_setInit('langavail', $lang_list); - } - } - - /** - * Enable an IMAP extension (see RFC 5161). - * - * @param array $exts The extensions to enable. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _enable($exts) - { - if (!empty($exts) && $this->_capability('ENABLE')) { - $c = $this->_capability(); - $todo = array(); - - // Only enable non-enabled extensions. - foreach ($exts as $val) { - if (!$c->isEnabled($val)) { - $c->enable($val); - $todo[] = $val; - } - } - - if (!empty($todo)) { - $cmd = $this->_command('ENABLE')->add($todo); - $cmd->on_error = function() use ($todo, $c) { - /* Something went wrong... disable the extensions. */ - foreach ($todo as $val) { - $c->enable($val, false); - } - }; - $this->_cmdQueue[] = $cmd; - } - } - } - - /** - * Parse an ENABLED response (RFC 5161 [3.2]). - * - * @param Horde_Imap_Client_Tokenize $data The server response. - */ - protected function _parseEnabled(Horde_Imap_Client_Tokenize $data) - { - $c = $this->_capability(); - - foreach ($data->flushIterator() as $val) { - $c->enable($val); - } - } - - /** - */ - protected function _openMailbox(Horde_Imap_Client_Mailbox $mailbox, $mode) - { - $c = $this->_capability(); - $qresync = $c->isEnabled('QRESYNC'); - - $cmd = $this->_command( - ($mode == Horde_Imap_Client::OPEN_READONLY) ? 'EXAMINE' : 'SELECT' - )->add( - $this->_getMboxFormatOb($mailbox) - ); - $pipeline = $this->_pipeline($cmd); - - /* If QRESYNC is available, synchronize the mailbox. */ - if ($qresync) { - $this->_initCache(); - $md = $this->_cache->getMetaData($mailbox, null, array(self::CACHE_MODSEQ, 'uidvalid')); - - /* CACHE_MODSEQ can be set but 0 (NOMODSEQ was returned). */ - if (!empty($md[self::CACHE_MODSEQ])) { - if ($uids = $this->_cache->get($mailbox)) { - $uids = $this->getIdsOb($uids); - - /* Check for extra long UID string. Assume that any - * server that can handle QRESYNC can also handle long - * input strings (at least 8 KB), so 7 KB is as good as - * any guess as to an upper limit. If this occurs, provide - * a range string (min -> max) instead. */ - if (strlen($uid_str = $uids->tostring_sort) > 7000) { - $uid_str = $uids->range_string; - } - } else { - $uid_str = null; - } - - /* Several things can happen with a QRESYNC: - * 1. UIDVALIDITY may have changed. If so, we need to expire - * the cache immediately (done below). - * 2. NOMODSEQ may have been returned. We can keep current - * message cache data but won't be able to do flag caching. - * 3. VANISHED/FETCH information was returned. These responses - * will have already been handled by those response handlers. - * 4. We are already synced with the local server in which - * case it acts like a normal EXAMINE/SELECT. */ - $cmd->add(new Horde_Imap_Client_Data_Format_List(array( - 'QRESYNC', - new Horde_Imap_Client_Data_Format_List(array_filter(array( - $md['uidvalid'], - $md[self::CACHE_MODSEQ], - $uid_str - ))) - ))); - } - - /* Let the 'CLOSED' response code handle mailbox switching if - * QRESYNC is active. */ - if ($this->_selected) { - $pipeline->data['qresyncmbox'] = array($mailbox, $mode); - } else { - $this->_changeSelected($mailbox, $mode); - } - } else { - if (!$c->isEnabled('CONDSTORE') && - $this->_initCache() && - $c->query('CONDSTORE')) { - /* Activate CONDSTORE now if ENABLE is not available. */ - $cmd->add(new Horde_Imap_Client_Data_Format_List('CONDSTORE')); - $c->enable('CONDSTORE'); - } - - $this->_changeSelected($mailbox, $mode); - } - - try { - $this->_sendCmd($pipeline); - } catch (Horde_Imap_Client_Exception_ServerResponse $e) { - // An EXAMINE/SELECT failure with a return of 'NO' will cause the - // current mailbox to be unselected. - if ($e->status === Horde_Imap_Client_Interaction_Server::NO) { - $this->_changeSelected(null); - $this->_mode = 0; - if (!$e->getCode()) { - $e = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Could not open mailbox \"%s\"."), - Horde_Imap_Client_Exception::MAILBOX_NOOPEN - ); - $e->messagePrintf(array($mailbox)); - } - } - throw $e; - } - - if ($qresync) { - /* Mailbox is fully sync'd. */ - $this->_mailboxOb()->sync = true; - } - } - - /** - */ - protected function _createMailbox(Horde_Imap_Client_Mailbox $mailbox, $opts) - { - $cmd = $this->_command('CREATE')->add( - $this->_getMboxFormatOb($mailbox) - ); - - // RFC 6154 Sec. 3 - if (!empty($opts['special_use'])) { - $use = new Horde_Imap_Client_Data_Format_List('USE'); - $use->add( - new Horde_Imap_Client_Data_Format_List($opts['special_use']) - ); - $cmd->add($use); - } - - // CREATE returns no untagged information (RFC 3501 [6.3.3]) - $this->_sendCmd($cmd); - } - - /** - */ - protected function _deleteMailbox(Horde_Imap_Client_Mailbox $mailbox) - { - // Some IMAP servers will not allow a delete of a currently open - // mailbox. - if ($mailbox->equals($this->_selected)) { - $this->close(); - } - - $cmd = $this->_command('DELETE')->add( - $this->_getMboxFormatOb($mailbox) - ); - - try { - // DELETE returns no untagged information (RFC 3501 [6.3.4]) - $this->_sendCmd($cmd); - } catch (Horde_Imap_Client_Exception $e) { - // Some IMAP servers won't allow a mailbox delete unless all - // messages in that mailbox are deleted. - $this->expunge($mailbox, array( - 'delete' => true - )); - $this->_sendCmd($cmd); - } - } - - /** - */ - protected function _renameMailbox(Horde_Imap_Client_Mailbox $old, - Horde_Imap_Client_Mailbox $new) - { - // Some IMAP servers will not allow a rename of a currently open - // mailbox. - if ($old->equals($this->_selected)) { - $this->close(); - } - - // RENAME returns no untagged information (RFC 3501 [6.3.5]) - $this->_sendCmd( - $this->_command('RENAME')->add(array( - $this->_getMboxFormatOb($old), - $this->_getMboxFormatOb($new) - )) - ); - } - - /** - */ - protected function _subscribeMailbox(Horde_Imap_Client_Mailbox $mailbox, - $subscribe) - { - // SUBSCRIBE/UNSUBSCRIBE returns no untagged information (RFC 3501 - // [6.3.6 & 6.3.7]) - $this->_sendCmd( - $this->_command( - $subscribe ? 'SUBSCRIBE' : 'UNSUBSCRIBE' - )->add( - $this->_getMboxFormatOb($mailbox) - ) - ); - } - - /** - */ - protected function _listMailboxes($pattern, $mode, $options) - { - // RFC 5258 [3.1]: Use LSUB for MBOX_SUBSCRIBED if no other server - // return options are specified. - if (($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) && - !array_intersect(array_keys($options), array('attributes', 'children', 'recursivematch', 'remote', 'special_use', 'status'))) { - return $this->_getMailboxList( - $pattern, - Horde_Imap_Client::MBOX_SUBSCRIBED, - array( - 'flat' => !empty($options['flat']), - 'no_listext' => true - ) - ); - } - - // Get the list of subscribed/unsubscribed mailboxes. Since LSUB is - // not guaranteed to have correct attributes, we must use LIST to - // ensure we receive the correct information. - if (($mode != Horde_Imap_Client::MBOX_ALL) && - !$this->_capability('LIST-EXTENDED')) { - $subscribed = $this->_getMailboxList( - $pattern, - Horde_Imap_Client::MBOX_SUBSCRIBED, - array('flat' => true) - ); - - // If mode is subscribed, and 'flat' option is true, we can - // return now. - if (($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) && - !empty($options['flat'])) { - return $subscribed; - } - } else { - $subscribed = null; - } - - return $this->_getMailboxList($pattern, $mode, $options, $subscribed); - } - - /** - * Obtain a list of mailboxes. - * - * @param array $pattern The mailbox search pattern(s). - * @param integer $mode Which mailboxes to return. - * @param array $options Additional options. 'no_listext' will skip - * using the LIST-EXTENDED capability. - * @param array $subscribed A list of subscribed mailboxes. - * - * @return array See listMailboxes((). - * - * @throws Horde_Imap_Client_Exception - */ - protected function _getMailboxList($pattern, $mode, $options, - $subscribed = null) - { - // Setup entry for use in _parseList(). - $pipeline = $this->_pipeline(); - $pipeline->data['mailboxlist'] = array( - 'ext' => false, - 'mode' => $mode, - 'opts' => $options, - /* Can't use array_merge here because it will destroy any mailbox - * name (key) that is "numeric". */ - 'sub' => (is_null($subscribed) ? null : array_flip(array_map('strval', $subscribed)) + array('INBOX' => true)) - ); - $pipeline->data['listresponse'] = array(); - - $cmds = array(); - $return_opts = new Horde_Imap_Client_Data_Format_List(); - - if ($this->_capability('LIST-EXTENDED') && - empty($options['no_listext'])) { - $cmd = $this->_command('LIST'); - $pipeline->data['mailboxlist']['ext'] = true; - - $select_opts = new Horde_Imap_Client_Data_Format_List(); - $subscribed = false; - - switch ($mode) { - case Horde_Imap_Client::MBOX_ALL_SUBSCRIBED: - case Horde_Imap_Client::MBOX_UNSUBSCRIBED: - $return_opts->add('SUBSCRIBED'); - break; - - case Horde_Imap_Client::MBOX_SUBSCRIBED: - case Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS: - $select_opts->add('SUBSCRIBED'); - $return_opts->add('SUBSCRIBED'); - $subscribed = true; - break; - } - - if (!empty($options['remote'])) { - $select_opts->add('REMOTE'); - } - - if (!empty($options['recursivematch'])) { - $select_opts->add('RECURSIVEMATCH'); - } - - if (!empty($select_opts)) { - $cmd->add($select_opts); - } - - $cmd->add(''); - - $tmp = new Horde_Imap_Client_Data_Format_List(); - foreach ($pattern as $val) { - if ($subscribed && (strcasecmp($val, 'INBOX') === 0)) { - $cmds[] = $this->_command('LIST')->add(array( - '', - 'INBOX' - )); - } else { - $tmp->add($this->_getMboxFormatOb($val, true)); - } - } - - if (count($tmp)) { - $cmd->add($tmp); - $cmds[] = $cmd; - } - - if (!empty($options['children'])) { - $return_opts->add('CHILDREN'); - } - - if (!empty($options['special_use'])) { - $return_opts->add('SPECIAL-USE'); - } - } else { - foreach ($pattern as $val) { - $cmds[] = $this->_command( - ($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) ? 'LSUB' : 'LIST' - )->add(array( - '', - $this->_getMboxFormatOb($val, true) - )); - } - } - - /* LIST-STATUS does NOT depend on LIST-EXTENDED. */ - if (!empty($options['status']) && - $this->_capability('LIST-STATUS')) { - $available_status = array( - Horde_Imap_Client::STATUS_MESSAGES, - Horde_Imap_Client::STATUS_RECENT, - Horde_Imap_Client::STATUS_UIDNEXT, - Horde_Imap_Client::STATUS_UIDVALIDITY, - Horde_Imap_Client::STATUS_UNSEEN, - Horde_Imap_Client::STATUS_HIGHESTMODSEQ - ); - - $status_opts = array(); - foreach (array_intersect($this->_statusFields, $available_status) as $key => $val) { - if ($options['status'] & $val) { - $status_opts[] = $key; - } - } - - if (count($status_opts)) { - $return_opts->add(array( - 'STATUS', - new Horde_Imap_Client_Data_Format_List( - array_map('Horde_String::upper', $status_opts) - ) - )); - } - } - - foreach ($cmds as $val) { - if (count($return_opts)) { - $val->add(array( - 'RETURN', - $return_opts - )); - } - - $pipeline->add($val); - } - - try { - $lr = $this->_sendCmd($pipeline)->data['listresponse']; - } catch (Horde_Imap_Client_Exception_ServerResponse $e) { - /* Archiveopteryx 3.1.3 can't process empty list-select-opts list. - * Retry using base IMAP4rev1 functionality. */ - if (($e->status === Horde_Imap_Client_Interaction_Server::BAD) && - $this->_capability('LIST-EXTENDED')) { - $this->_capability()->remove('LIST-EXTENDED'); - return $this->_listMailboxes($pattern, $mode, $options); - } - - throw $e; - } - - if (!empty($options['flat'])) { - return array_values($lr); - } - - /* Add in STATUS return, if needed. */ - if (!empty($options['status']) && $this->_capability('LIST-STATUS')) { - foreach($lr as $val_utf8 => $tmp) { - $lr[$val_utf8]['status'] = $this->_prepareStatusResponse($status_opts, $val_utf8); - } - } - - return $lr; - } - - /** - * Parse a LIST/LSUB response (RFC 3501 [7.2.2 & 7.2.3]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The server response (includes - * type as first token). - * - * @throws Horde_Imap_Client_Exception - */ - protected function _parseList( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - $data->next(); - $attr = null; - $attr_raw = $data->flushIterator(); - $delimiter = $data->next(); - $mbox = Horde_Imap_Client_Mailbox::get( - $data->next(), - !$this->_capability()->isEnabled('UTF8=ACCEPT') - ); - $ml = $pipeline->data['mailboxlist']; - - switch ($ml['mode']) { - case Horde_Imap_Client::MBOX_ALL_SUBSCRIBED: - case Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS: - case Horde_Imap_Client::MBOX_UNSUBSCRIBED: - $attr = array_flip(array_map('Horde_String::lower', $attr_raw)); - - /* Subscribed list is in UTF-8. */ - if (is_null($ml['sub']) && - !isset($attr['\\subscribed']) && - (strcasecmp($mbox, 'INBOX') === 0)) { - $attr['\\subscribed'] = 1; - } elseif (isset($ml['sub'][strval($mbox)])) { - $attr['\\subscribed'] = 1; - } - break; - } - - switch ($ml['mode']) { - case Horde_Imap_Client::MBOX_SUBSCRIBED_EXISTS: - if (isset($attr['\\nonexistent']) || - !isset($attr['\\subscribed'])) { - return; - } - break; - - case Horde_Imap_Client::MBOX_UNSUBSCRIBED: - if (isset($attr['\\subscribed'])) { - return; - } - break; - } - - if (!empty($ml['opts']['flat'])) { - $pipeline->data['listresponse'][] = $mbox; - return; - } - - $tmp = array( - 'delimiter' => $delimiter, - 'mailbox' => $mbox - ); - - if ($attr || !empty($ml['opts']['attributes'])) { - if (is_null($attr)) { - $attr = array_flip(array_map('Horde_String::lower', $attr_raw)); - } - - /* RFC 5258 [3.4]: inferred attributes. */ - if ($ml['ext']) { - if (isset($attr['\\noinferiors'])) { - $attr['\\hasnochildren'] = 1; - } - if (isset($attr['\\nonexistent'])) { - $attr['\\noselect'] = 1; - } - } - $tmp['attributes'] = array_keys($attr); - } - - if ($data->next() !== false) { - $tmp['extended'] = $data->flushIterator(); - } - - $pipeline->data['listresponse'][strval($mbox)] = $tmp; - } - - /** - */ - protected function _status($mboxes, $flags) - { - $on_error = null; - $out = $to_process = array(); - $pipeline = $this->_pipeline(); - $unseen_flags = array( - Horde_Imap_Client::STATUS_FIRSTUNSEEN, - Horde_Imap_Client::STATUS_UNSEEN - ); - - foreach ($mboxes as $mailbox) { - /* If FLAGS/PERMFLAGS/UIDNOTSTICKY/FIRSTUNSEEN are needed, we must - * do a SELECT/EXAMINE to get this information (data will be - * caught in the code below). */ - if (($flags & Horde_Imap_Client::STATUS_FIRSTUNSEEN) || - ($flags & Horde_Imap_Client::STATUS_FLAGS) || - ($flags & Horde_Imap_Client::STATUS_PERMFLAGS) || - ($flags & Horde_Imap_Client::STATUS_UIDNOTSTICKY)) { - $this->openMailbox($mailbox); - } - - $mbox_ob = $this->_mailboxOb($mailbox); - $data = $query = array(); - - foreach ($this->_statusFields as $key => $val) { - if (!($val & $flags)) { - continue; - } - - if ($val == Horde_Imap_Client::STATUS_HIGHESTMODSEQ) { - $c = $this->_capability(); - - /* Don't include modseq returns if server does not support - * it. */ - if (!$c->query('CONDSTORE')) { - continue; - } - - /* Even though CONDSTORE is available, it may not yet have - * been enabled. */ - $c->enable('CONDSTORE'); - $on_error = function() use ($c) { - $c->enable('CONDSTORE', false); - }; - } - - if ($mailbox->equals($this->_selected)) { - if (!is_null($tmp = $mbox_ob->getStatus($val))) { - $data[$key] = $tmp; - } elseif (($val == Horde_Imap_Client::STATUS_UIDNEXT) && - ($flags & Horde_Imap_Client::STATUS_UIDNEXT_FORCE)) { - /* UIDNEXT is not mandatory. */ - if ($mbox_ob->getStatus(Horde_Imap_Client::STATUS_MESSAGES) == 0) { - $data[$key] = 0; - } else { - $fquery = new Horde_Imap_Client_Fetch_Query(); - $fquery->uid(); - $fetch_res = $this->fetch($this->_selected, $fquery, array( - 'ids' => $this->getIdsOb(Horde_Imap_Client_Ids::LARGEST) - )); - $data[$key] = $fetch_res->first()->getUid() + 1; - } - } elseif (in_array($val, $unseen_flags)) { - /* RFC 3501 [6.3.1] - FIRSTUNSEEN information is not - * mandatory. If missing in EXAMINE/SELECT results, we - * need to do a search. An UNSEEN count also requires - * a search. */ - $squery = new Horde_Imap_Client_Search_Query(); - $squery->flag(Horde_Imap_Client::FLAG_SEEN, false); - $search = $this->search($mailbox, $squery, array( - 'results' => array( - Horde_Imap_Client::SEARCH_RESULTS_MIN, - Horde_Imap_Client::SEARCH_RESULTS_COUNT - ), - 'sequence' => true - )); - - $mbox_ob->setStatus(Horde_Imap_Client::STATUS_FIRSTUNSEEN, $search['min']); - $mbox_ob->setStatus(Horde_Imap_Client::STATUS_UNSEEN, $search['count']); - - $data[$key] = $mbox_ob->getStatus($val); - } - } else { - $query[] = $key; - } - } - - $out[strval($mailbox)] = $data; - - if (count($query)) { - $cmd = $this->_command('STATUS')->add(array( - $this->_getMboxFormatOb($mailbox), - new Horde_Imap_Client_Data_Format_List( - array_map('Horde_String::upper', $query) - ) - )); - $cmd->on_error = $on_error; - - $pipeline->add($cmd); - $to_process[] = array($query, $mailbox); - } - } - - if (count($pipeline)) { - $this->_sendCmd($pipeline); - - foreach ($to_process as $val) { - $out[strval($val[1])] += $this->_prepareStatusResponse($val[0], $val[1]); - } - } - - return $out; - } - - /** - * Parse a STATUS response (RFC 3501 [7.2.4]). - * - * @param Horde_Imap_Client_Tokenize $data Token data - */ - protected function _parseStatus(Horde_Imap_Client_Tokenize $data) - { - // Mailbox name is in UTF7-IMAP (unless UTF8 has been enabled). - $mbox_ob = $this->_mailboxOb( - Horde_Imap_Client_Mailbox::get( - $data->next(), - !$this->_capability()->isEnabled('UTF8=ACCEPT') - ) - ); - - $data->next(); - - while (($k = $data->next()) !== false) { - $mbox_ob->setStatus( - $this->_statusFields[Horde_String::lower($k)], - $data->next() - ); - } - } - - /** - * Prepares a status response for a mailbox. - * - * @param array $request The status keys to return. - * @param string $mailbox The mailbox to query. - */ - protected function _prepareStatusResponse($request, $mailbox) - { - $mbox_ob = $this->_mailboxOb($mailbox); - $out = array(); - - foreach ($request as $val) { - $out[$val] = $mbox_ob->getStatus($this->_statusFields[$val]); - } - - return $out; - } - - /** - */ - protected function _append(Horde_Imap_Client_Mailbox $mailbox, $data, - $options) - { - $c = $this->_capability(); - - // Check for MULTIAPPEND extension (RFC 3502) - if ((count($data) > 1) && !$c->query('MULTIAPPEND')) { - $result = $this->getIdsOb(); - foreach (array_keys($data) as $key) { - $res = $this->_append($mailbox, array($data[$key]), $options); - if (($res === true) || ($result === true)) { - $result = true; - } else { - $result->add($res); - } - } - return $result; - } - - // Check for extensions. - $binary = $c->query('BINARY'); - $catenate = $c->query('CATENATE'); - $utf8 = $c->isEnabled('UTF8=ACCEPT'); - - $asize = 0; - - $cmd = $this->_command('APPEND')->add( - $this->_getMboxFormatOb($mailbox) - ); - $cmd->literal8 = true; - - foreach (array_keys($data) as $key) { - if (!empty($data[$key]['flags'])) { - $tmp = new Horde_Imap_Client_Data_Format_List(); - foreach ($data[$key]['flags'] as $val) { - /* Ignore recent flag. RFC 3501 [9]: flag definition */ - if (strcasecmp($val, Horde_Imap_Client::FLAG_RECENT) !== 0) { - $tmp->add($val); - } - } - $cmd->add($tmp); - } - - if (!empty($data[$key]['internaldate'])) { - $cmd->add(new Horde_Imap_Client_Data_Format_DateTime($data[$key]['internaldate'])); - } - - $adata = null; - - if (is_array($data[$key]['data'])) { - if ($catenate) { - $cmd->add('CATENATE'); - $tmp = new Horde_Imap_Client_Data_Format_List(); - } else { - $data_stream = new Horde_Stream_Temp(); - } - - foreach ($data[$key]['data'] as $v) { - switch ($v['t']) { - case 'text': - if ($catenate) { - $tdata = $this->_appendData($v['v'], $asize); - if ($utf8) { - /* RFC 6855 [4]: CATENATE UTF8 extension. */ - $tdata->forceBinary(); - $tmp->add(array( - 'UTF8', - new Horde_Imap_Client_Data_Format_List($tdata) - )); - } else { - $tmp->add(array( - 'TEXT', - $tdata - )); - } - } else { - if (is_resource($v['v'])) { - rewind($v['v']); - } - $data_stream->add($v['v']); - } - break; - - case 'url': - if ($catenate) { - $tmp->add(array( - 'URL', - new Horde_Imap_Client_Data_Format_Astring($v['v']) - )); - } else { - $data_stream->add($this->_convertCatenateUrl($v['v'])); - } - break; - } - } - - if ($catenate) { - $cmd->add($tmp); - } else { - $adata = $this->_appendData($data_stream->stream, $asize); - } - } else { - $adata = $this->_appendData($data[$key]['data'], $asize); - } - - if (!is_null($adata)) { - if ($utf8) { - /* RFC 6855 [4]: APPEND UTF8 extension. */ - $adata->forceBinary(); - $cmd->add(array( - 'UTF8', - new Horde_Imap_Client_Data_Format_List($adata) - )); - } else { - $cmd->add($adata); - } - } - } - - /* Although it is normally more efficient to use LITERAL+, disable if - * payload is over 50 KB because it allows the server to throw error - * before we potentially push a lot of data to server that would - * otherwise be ignored (see RFC 4549 [4.2.2.3]). - * Additionally, since so many IMAP servers have issues with APPEND - * + BINARY, don't use LITERAL+ since servers may send BAD - * (incorrectly) after initial command. */ - $cmd->literalplus = (($asize < (1024 * 50)) && !$binary); - - // If the mailbox is currently selected read-only, we need to close - // because some IMAP implementations won't allow an append. And some - // implementations don't support append on ANY open mailbox. Be safe - // and always make sure we are in a non-selected state. - $this->close(); - - try { - $resp = $this->_sendCmd($cmd); - } catch (Horde_Imap_Client_Exception $e) { - switch ($e->getCode()) { - case $e::CATENATE_BADURL: - case $e::CATENATE_TOOBIG: - /* Cyrus 2.4 (at least as of .14) has a broken CATENATE (see - * Bug #11111). Regardless, if CATENATE is broken, we can try - * to fallback to APPEND. */ - $c->remove('CATENATE'); - return $this->_append($mailbox, $data, $options); - - case $e::DISCONNECT: - /* Workaround broken literal8 on Cyrus. */ - if ($binary) { - // Need to re-login first before removing capability. - $this->login(); - $c->remove('BINARY'); - return $this->_append($mailbox, $data, $options); - } - break; - } - - if (!empty($options['create']) && - !empty($e->resp_data['trycreate'])) { - $this->createMailbox($mailbox); - unset($options['create']); - return $this->_append($mailbox, $data, $options); - } - - /* RFC 3516/4466 says we should be able to append binary data - * using literal8 "~{#} format", but it doesn't seem to work on - * all servers tried (UW-IMAP/Cyrus). Do a last-ditch check for - * broken BINARY and attempt to fix here. */ - if ($c->query('BINARY') && - ($e instanceof Horde_Imap_Client_Exception_ServerResponse)) { - switch ($e->status) { - case Horde_Imap_Client_Interaction_Server::BAD: - case Horde_Imap_Client_Interaction_Server::NO: - $c->remove('BINARY'); - return $this->_append($mailbox, $data, $options); - } - } - - throw $e; - } - - /* If we reach this point and have data in 'appenduid', UIDPLUS (RFC - * 4315) has done the dirty work for us. */ - return isset($resp->data['appenduid']) - ? $resp->data['appenduid'] - : true; - } - - /** - * Prepares append message data for insertion into the IMAP command - * string. - * - * @param mixed $data Either a resource or a string. - * @param integer &$asize Total append size. - * - * @return Horde_Imap_Client_Data_Format_String_Nonascii The data object. - */ - protected function _appendData($data, &$asize) - { - if (is_resource($data)) { - rewind($data); - } - - /* Since this is body text, with possible embedded charset - * information, non-ASCII characters are supported. */ - $ob = new Horde_Imap_Client_Data_Format_String_Nonascii($data, array( - 'eol' => true, - 'skipscan' => true - )); - - // APPEND data MUST be sent in a literal (RFC 3501 [6.3.11]). - $ob->forceLiteral(); - - $asize += $ob->length(); - - return $ob; - } - - /** - * Converts a CATENATE URL to stream data. - * - * @param string $url The CATENATE URL. - * - * @return resource A stream containing the data. - */ - protected function _convertCatenateUrl($url) - { - $e = $part = null; - $url = new Horde_Imap_Client_Url_Imap($url); - - if (!is_null($url->mailbox) && !is_null($url->uid)) { - try { - $status_res = is_null($url->uidvalidity) - ? null - : $this->status($url->mailbox, Horde_Imap_Client::STATUS_UIDVALIDITY); - - if (is_null($status_res) || - ($status_res['uidvalidity'] == $url->uidvalidity)) { - if (!isset($this->_temp['catenate_ob'])) { - $this->_temp['catenate_ob'] = new Horde_Imap_Client_Socket_Catenate($this); - } - $part = $this->_temp['catenate_ob']->fetchFromUrl($url); - } - } catch (Horde_Imap_Client_Exception $e) {} - } - - if (is_null($part)) { - $message = 'Bad IMAP URL given in CATENATE data: ' . strval($url); - if ($e) { - $message .= ' ' . $e->getMessage(); - } - - throw new InvalidArgumentException($message); - } - - return $part; - } - - /** - */ - protected function _check() - { - // CHECK returns no untagged information (RFC 3501 [6.4.1]) - $this->_sendCmd($this->_command('CHECK')); - } - - /** - */ - protected function _close($options) - { - if (empty($options['expunge'])) { - if ($this->_capability('UNSELECT')) { - // RFC 3691 defines 'UNSELECT' for precisely this purpose - $this->_sendCmd($this->_command('UNSELECT')); - } else { - /* RFC 3501 [6.4.2]: to close a mailbox without expunge, - * select a non-existent mailbox. */ - try { - $this->_sendCmd($this->_command('EXAMINE')->add( - $this->_getMboxFormatOb("\24nonexist\24") - )); - - /* Not pipelining, since the odds that this CLOSE is even - * needed is tiny; and it returns BAD, which should be - * avoided, if possible. */ - $this->_sendCmd($this->_command('CLOSE')); - } catch (Horde_Imap_Client_Exception_ServerResponse $e) { - // Ignore error; it is expected. - } - } - } else { - // If caching, we need to know the UIDs being deleted, so call - // expunge() before calling close(). - if ($this->_initCache(true)) { - $this->expunge($this->_selected); - } - - // CLOSE returns no untagged information (RFC 3501 [6.4.2]) - $this->_sendCmd($this->_command('CLOSE')); - } - } - - /** - */ - protected function _expunge($options) - { - $expunged_ob = $modseq = null; - $ids = $options['ids']; - $list_msgs = !empty($options['list']); - $mailbox = $this->_selected; - $uidplus = $this->_capability('UIDPLUS'); - $unflag = array(); - $use_cache = $this->_initCache(true); - - if ($ids->all) { - if (!$uidplus || $list_msgs || $use_cache) { - $ids = $this->resolveIds($mailbox, $ids, 2); - } - } elseif ($uidplus) { - /* If QRESYNC is not available, and we are returning the list of - * expunged messages (or we are caching), we have to make sure we - * have a mapping of Sequence -> UIDs. If we have QRESYNC, the - * server SHOULD return a VANISHED response with UIDs. However, - * even if the server returns EXPUNGEs instead, we can use - * vanished() to grab the list. */ - unset($this->_temp['search_save']); - if ($this->_capability()->isEnabled('QRESYNC')) { - $ids = $this->resolveIds($mailbox, $ids, 1); - if ($list_msgs) { - $modseq = $this->_mailboxOb()->getStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ); - } - } else { - $ids = $this->resolveIds($mailbox, $ids, ($list_msgs || $use_cache) ? 2 : 1); - } - if (!empty($this->_temp['search_save'])) { - $ids = $this->getIdsOb(Horde_Imap_Client_Ids::SEARCH_RES); - } - } else { - /* Without UIDPLUS, need to temporarily unflag all messages marked - * as deleted but not a part of requested IDs to delete. Use NOT - * searches to accomplish this goal. */ - $squery = new Horde_Imap_Client_Search_Query(); - $squery->flag(Horde_Imap_Client::FLAG_DELETED, true); - $squery->ids($ids, true); - - $s_res = $this->search($mailbox, $squery, array( - 'results' => array( - Horde_Imap_Client::SEARCH_RESULTS_MATCH, - Horde_Imap_Client::SEARCH_RESULTS_SAVE - ) - )); - - $this->store($mailbox, array( - 'ids' => empty($s_res['save']) ? $s_res['match'] : $this->getIdsOb(Horde_Imap_Client_Ids::SEARCH_RES), - 'remove' => array(Horde_Imap_Client::FLAG_DELETED) - )); - - $unflag = $s_res['match']; - } - - if ($list_msgs) { - $expunged_ob = $this->getIdsOb(); - $this->_temp['expunged'] = $expunged_ob; - } - - /* Always use UID EXPUNGE if available. */ - if ($uidplus) { - /* We can only pipeline STORE w/ EXPUNGE if using UIDs and UIDPLUS - * is available. */ - if (empty($options['delete'])) { - $pipeline = $this->_pipeline(); - } else { - $pipeline = $this->_storeCmd(array( - 'add' => array( - Horde_Imap_Client::FLAG_DELETED - ), - 'ids' => $ids - )); - } - - foreach ($ids->split(2000) as $val) { - $pipeline->add( - $this->_command('UID EXPUNGE')->add($val) - ); - } - - $resp = $this->_sendCmd($pipeline); - } else { - if (!empty($options['delete'])) { - $this->store($mailbox, array( - 'add' => array(Horde_Imap_Client::FLAG_DELETED), - 'ids' => $ids - )); - } - - if ($use_cache || $list_msgs) { - $this->_sendCmd($this->_command('EXPUNGE')); - } else { - /* This is faster than an EXPUNGE because the server will not - * return untagged EXPUNGE responses. We can only do this if - * we are not updating cache information. */ - $this->close(array('expunge' => true)); - } - } - - unset($this->_temp['expunged']); - - if (!empty($unflag)) { - $this->store($mailbox, array( - 'add' => array(Horde_Imap_Client::FLAG_DELETED), - 'ids' => $unflag - )); - } - - if (!is_null($modseq) && !empty($resp->data['expunge_seen'])) { - /* There's a chance we actually did a full map of sequence -> UID, - * but this code should never be reached in the first place so - * be ultra-safe and just do a full VANISHED search. */ - $expunged_ob = $this->vanished($mailbox, $modseq, array( - 'ids' => $ids - )); - $this->_deleteMsgs($mailbox, $expunged_ob, array( - 'pipeline' => $resp - )); - } - - return $expunged_ob; - } - - /** - * Parse a VANISHED response (RFC 7162 [3.2.10]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The response data. - */ - protected function _parseVanished( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - /* There are two forms of VANISHED. VANISHED (EARLIER) will be sent - * in a FETCH (VANISHED) or SELECT/EXAMINE (QRESYNC) call. - * If this is the case, we can go ahead and update the cache - * immediately (we know we are caching or else QRESYNC would not be - * enabled). HIGHESTMODSEQ information will be updated via the tagged - * response. */ - if (($curr = $data->next()) === true) { - if (Horde_String::upper($data->next()) === 'EARLIER') { - /* Caching is guaranteed to be active if we are using - * QRESYNC. */ - $data->next(); - $vanished = $this->getIdsOb($data->next()); - if (isset($pipeline->data['vanished'])) { - $pipeline->data['vanished']->add($vanished); - } else { - $this->_deleteMsgs($this->_selected, $vanished, array( - 'pipeline' => $pipeline - )); - } - } - } else { - /* The second form is just VANISHED. This is analogous to EXPUNGE - * and requires the message count to decrement. */ - $this->_deleteMsgs($this->_selected, $this->getIdsOb($curr), array( - 'decrement' => true, - 'pipeline' => $pipeline - )); - } - } - - /** - * Search a mailbox. This driver supports all IMAP4rev1 search criteria - * as defined in RFC 3501. - */ - protected function _search($query, $options) - { - $sort_criteria = array( - Horde_Imap_Client::SORT_ARRIVAL => 'ARRIVAL', - Horde_Imap_Client::SORT_CC => 'CC', - Horde_Imap_Client::SORT_DATE => 'DATE', - Horde_Imap_Client::SORT_DISPLAYFROM => 'DISPLAYFROM', - Horde_Imap_Client::SORT_DISPLAYTO => 'DISPLAYTO', - Horde_Imap_Client::SORT_FROM => 'FROM', - Horde_Imap_Client::SORT_REVERSE => 'REVERSE', - Horde_Imap_Client::SORT_RELEVANCY => 'RELEVANCY', - // This is a bogus entry to allow the sort options check to - // correctly work below. - Horde_Imap_Client::SORT_SEQUENCE => 'SEQUENCE', - Horde_Imap_Client::SORT_SIZE => 'SIZE', - Horde_Imap_Client::SORT_SUBJECT => 'SUBJECT', - Horde_Imap_Client::SORT_TO => 'TO' - ); - - $results_criteria = array( - Horde_Imap_Client::SEARCH_RESULTS_COUNT => 'COUNT', - Horde_Imap_Client::SEARCH_RESULTS_MATCH => 'ALL', - Horde_Imap_Client::SEARCH_RESULTS_MAX => 'MAX', - Horde_Imap_Client::SEARCH_RESULTS_MIN => 'MIN', - Horde_Imap_Client::SEARCH_RESULTS_RELEVANCY => 'RELEVANCY', - Horde_Imap_Client::SEARCH_RESULTS_SAVE => 'SAVE' - ); - - // Check if the server supports sorting (RFC 5256). - $esearch = $return_sort = $server_seq_sort = $server_sort = false; - if (!empty($options['sort'])) { - /* Make sure sort options are correct. If not, default to no - * sort. */ - if (count(array_intersect($options['sort'], array_keys($sort_criteria))) === 0) { - unset($options['sort']); - } else { - $return_sort = true; - - if ($this->_capability('SORT')) { - /* Make sure server supports DISPLAYFROM & DISPLAYTO. */ - $server_sort = - !array_intersect($options['sort'], array(Horde_Imap_Client::SORT_DISPLAYFROM, Horde_Imap_Client::SORT_DISPLAYTO)) || - $this->_capability('SORT', 'DISPLAY'); - } - - /* If doing a sequence sort, need to do this on the client - * side. */ - if ($server_sort && - in_array(Horde_Imap_Client::SORT_SEQUENCE, $options['sort'])) { - $server_sort = false; - - /* Optimization: If doing only a sequence sort, just do a - * simple search and sort UIDs/sequences on client side. */ - switch (count($options['sort'])) { - case 1: - $server_seq_sort = true; - break; - - case 2: - $server_seq_sort = (reset($options['sort']) == Horde_Imap_Client::SORT_REVERSE); - break; - } - } - } - } - - $charset = is_null($options['_query']['charset']) - ? 'US-ASCII' - : $options['_query']['charset']; - $partial = false; - - if ($server_sort) { - $cmd = $this->_command( - empty($options['sequence']) ? 'UID SORT' : 'SORT' - ); - $results = array(); - - // Use ESEARCH (RFC 4466) response if server supports. - $esearch = false; - - // Check for ESORT capability (RFC 5267) - if ($this->_capability('ESORT')) { - foreach ($options['results'] as $val) { - if (isset($results_criteria[$val]) && - ($val != Horde_Imap_Client::SEARCH_RESULTS_SAVE)) { - $results[] = $results_criteria[$val]; - } - } - $esearch = true; - } - - // Add PARTIAL limiting (RFC 5267 [4.4]) - if ((!$esearch || !empty($options['partial'])) && - $this->_capability('CONTEXT', 'SORT')) { - /* RFC 5267 indicates RFC 4466 ESEARCH-like support, - * notwithstanding "real" RFC 4731 support. */ - $esearch = true; - - if (!empty($options['partial'])) { - /* Can't have both ALL and PARTIAL returns. */ - $results = array_diff($results, array('ALL')); - - $results[] = 'PARTIAL'; - $results[] = $options['partial']; - $partial = true; - } - } - - if ($esearch && empty($this->_init['noesearch'])) { - $cmd->add(array( - 'RETURN', - new Horde_Imap_Client_Data_Format_List($results) - )); - } - - $tmp = new Horde_Imap_Client_Data_Format_List(); - foreach ($options['sort'] as $val) { - if (isset($sort_criteria[$val])) { - $tmp->add($sort_criteria[$val]); - } - } - $cmd->add($tmp); - - /* Charset is mandatory for SORT (RFC 5256 [3]). - * If UTF-8 support is activated, a client MUST ONLY - * send the 'UTF-8' specification (RFC 6855 [3]; Errata 4029). */ - if (!$this->_capability()->isEnabled('UTF8=ACCEPT')) { - $cmd->add($charset); - } else { - $cmd->add('UTF-8'); - } - } else { - $cmd = $this->_command( - empty($options['sequence']) ? 'UID SEARCH' : 'SEARCH' - ); - $esearch = false; - $results = array(); - - // Check if the server supports ESEARCH (RFC 4731). - if ($this->_capability('ESEARCH')) { - foreach ($options['results'] as $val) { - if (isset($results_criteria[$val])) { - $results[] = $results_criteria[$val]; - } - } - $esearch = true; - } - - // Add PARTIAL limiting (RFC 5267 [4.4]). - if ((!$esearch || !empty($options['partial'])) && - $this->_capability('CONTEXT', 'SEARCH')) { - /* RFC 5267 indicates RFC 4466 ESEARCH-like support, - * notwithstanding "real" RFC 4731 support. */ - $esearch = true; - - if (!empty($options['partial'])) { - // Can't have both ALL and PARTIAL returns. - $results = array_diff($results, array('ALL')); - - $results[] = 'PARTIAL'; - $results[] = $options['partial']; - $partial = true; - } - } - - if ($esearch && empty($this->_init['noesearch'])) { - // Always use ESEARCH if available because it returns results - // in a more compact sequence-set list - $cmd->add(array( - 'RETURN', - new Horde_Imap_Client_Data_Format_List($results) - )); - } - - /* Charset is optional for SEARCH (RFC 3501 [6.4.4]). - * If UTF-8 support is activated, a client MUST NOT - * send the charset specification (RFC 6855 [3]; Errata 4029). */ - if (($charset != 'US-ASCII') && - !$this->_capability()->isEnabled('UTF8=ACCEPT')) { - $cmd->add(array( - 'CHARSET', - $options['_query']['charset'] - )); - } - } - - $cmd->add($options['_query']['query'], true); - - $pipeline = $this->_pipeline($cmd); - $pipeline->data['esearchresp'] = array(); - $er = &$pipeline->data['esearchresp']; - $pipeline->data['searchresp'] = $this->getIdsOb(array(), !empty($options['sequence'])); - $sr = &$pipeline->data['searchresp']; - - try { - $resp = $this->_sendCmd($pipeline); - } catch (Horde_Imap_Client_Exception $e) { - if (($e instanceof Horde_Imap_Client_Exception_ServerResponse) && - ($e->status === Horde_Imap_Client_Interaction_Server::NO) && - ($charset != 'US-ASCII')) { - /* RFC 3501 [6.4.4]: BADCHARSET response code is only a - * SHOULD return. If it doesn't exist, need to check for - * command status of 'NO'. List of supported charsets in - * the BADCHARSET response has already been parsed and stored - * at this point. */ - $this->search_charset->setValid($charset, false); - $e->setCode(Horde_Imap_Client_Exception::BADCHARSET); - } - - if (empty($this->_temp['search_retry'])) { - $this->_temp['search_retry'] = true; - - /* Bug #9842: Workaround broken Cyrus servers (as of - * 2.4.7). */ - if ($esearch && ($charset != 'US-ASCII')) { - $this->_capability()->remove('ESEARCH'); - $this->_setInit('noesearch', true); - - try { - return $this->_search($query, $options); - } catch (Horde_Imap_Client_Exception $e) {} - } - - /* Try to convert charset. */ - if (($e->getCode() === Horde_Imap_Client_Exception::BADCHARSET) && - ($charset != 'US-ASCII')) { - foreach ($this->search_charset->charsets as $val) { - $this->_temp['search_retry'] = 1; - $new_query = clone($query); - try { - $new_query->charset($val); - $options['_query'] = $new_query->build($this); - return $this->_search($new_query, $options); - } catch (Horde_Imap_Client_Exception $e) {} - } - } - - unset($this->_temp['search_retry']); - } - - throw $e; - } - - if ($return_sort && !$server_sort) { - if ($server_seq_sort) { - $sr->sort(); - if (reset($options['sort']) == Horde_Imap_Client::SORT_REVERSE) { - $sr->reverse(); - } - } else { - if (!isset($this->_temp['clientsort'])) { - $this->_temp['clientsort'] = new Horde_Imap_Client_Socket_ClientSort($this); - } - $sr = $this->getIdsOb($this->_temp['clientsort']->clientSort($sr, $options), !empty($options['sequence'])); - } - } - - if (!$partial && !empty($options['partial'])) { - $partial = $this->getIdsOb($options['partial'], true); - $min = $partial->min - 1; - - $sr = $this->getIdsOb( - array_slice($sr->ids, $min, $partial->max - $min), - !empty($options['sequence']) - ); - } - - $ret = array(); - foreach ($options['results'] as $val) { - switch ($val) { - case Horde_Imap_Client::SEARCH_RESULTS_COUNT: - $ret['count'] = ($esearch && !$partial) - ? $er['count'] - : count($sr); - break; - - case Horde_Imap_Client::SEARCH_RESULTS_MATCH: - $ret['match'] = $sr; - break; - - case Horde_Imap_Client::SEARCH_RESULTS_MAX: - $ret['max'] = $esearch - ? (!$partial && isset($er['max']) ? $er['max'] : null) - : (count($sr) ? max($sr->ids) : null); - break; - - case Horde_Imap_Client::SEARCH_RESULTS_MIN: - $ret['min'] = $esearch - ? (!$partial && isset($er['min']) ? $er['min'] : null) - : (count($sr) ? min($sr->ids) : null); - break; - - case Horde_Imap_Client::SEARCH_RESULTS_RELEVANCY: - $ret['relevancy'] = ($esearch && isset($er['relevancy'])) ? $er['relevancy'] : array(); - break; - - case Horde_Imap_Client::SEARCH_RESULTS_SAVE: - $this->_temp['search_save'] = $ret['save'] = $esearch ? empty($resp->data['searchnotsaved']) : false; - break; - } - } - - // Add modseq data, if needed. - if (!empty($er['modseq'])) { - $ret['modseq'] = $er['modseq']; - } - - unset($this->_temp['search_retry']); - - /* Check for EXPUNGEISSUED (RFC 2180 [4.3]/RFC 5530 [3]). */ - if (!empty($resp->data['expungeissued'])) { - $this->noop(); - } - - return $ret; - } - - /** - * Parse a SEARCH/SORT response (RFC 3501 [7.2.5]; RFC 4466 [3]; - * RFC 5256 [4]; RFC 5267 [3]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param array $data A list of IDs (message sequence numbers or UIDs). - */ - protected function _parseSearch( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - $data - ) - { - /* More than one search response may be sent. */ - $pipeline->data['searchresp']->add($data); - } - - /** - * Parse an ESEARCH response (RFC 4466 [2.6.2]) - * Format: (TAG "a567") UID COUNT 5 ALL 4:19,21,28 - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The server response. - */ - protected function _parseEsearch( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - // Ignore search correlator information - if ($data->next() === true) { - $data->flushIterator(false); - } - - // Ignore UID tag - $current = $data->next(); - if (Horde_String::upper($current) === 'UID') { - $current = $data->next(); - } - - do { - $val = $data->next(); - $tag = Horde_String::upper($current); - - switch ($tag) { - case 'ALL': - $this->_parseSearch($pipeline, $val); - break; - - case 'COUNT': - case 'MAX': - case 'MIN': - case 'MODSEQ': - case 'RELEVANCY': - $pipeline->data['esearchresp'][Horde_String::lower($tag)] = $val; - break; - - case 'PARTIAL': - // RFC 5267 [4.4] - $partial = $val->flushIterator(); - $this->_parseSearch($pipeline, end($partial)); - break; - } - } while (($current = $data->next()) !== false); - } - - /** - */ - protected function _setComparator($comparator) - { - $cmd = $this->_command('COMPARATOR'); - foreach ($comparator as $val) { - $cmd->add(new Horde_Imap_Client_Data_Format_Astring($val)); - } - $this->_sendCmd($cmd); - } - - /** - */ - protected function _getComparator() - { - $resp = $this->_sendCmd($this->_command('COMPARATOR')); - - return isset($resp->data['comparator']) - ? $resp->data['comparator'] - : null; - } - - /** - * Parse a COMPARATOR response (RFC 5255 [4.8]) - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The server response. - */ - protected function _parseComparator( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - $data - ) - { - $pipeline->data['comparator'] = $data->next(); - // Ignore optional matching comparator list - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportExtension - */ - protected function _thread($options) - { - $thread_criteria = array( - Horde_Imap_Client::THREAD_ORDEREDSUBJECT => 'ORDEREDSUBJECT', - Horde_Imap_Client::THREAD_REFERENCES => 'REFERENCES', - Horde_Imap_Client::THREAD_REFS => 'REFS' - ); - - $tsort = (isset($options['criteria'])) - ? (is_string($options['criteria']) ? Horde_String::upper($options['criteria']) : $thread_criteria[$options['criteria']]) - : 'ORDEREDSUBJECT'; - - if (!$this->_capability('THREAD', $tsort)) { - switch ($tsort) { - case 'ORDEREDSUBJECT': - if (empty($options['search'])) { - $ids = $this->getIdsOb(Horde_Imap_Client_Ids::ALL, !empty($options['sequence'])); - } else { - $search_res = $this->search($this->_selected, $options['search'], array('sequence' => !empty($options['sequence']))); - $ids = $search_res['match']; - } - - /* Do client-side ORDEREDSUBJECT threading. */ - $query = new Horde_Imap_Client_Fetch_Query(); - $query->envelope(); - $query->imapDate(); - - $fetch_res = $this->fetch($this->_selected, $query, array( - 'ids' => $ids - )); - - if (!isset($this->_temp['clientsort'])) { - $this->_temp['clientsort'] = new Horde_Imap_Client_Socket_ClientSort($this); - } - return $this->_temp['clientsort']->threadOrderedSubject($fetch_res, empty($options['sequence'])); - - case 'REFERENCES': - case 'REFS': - throw new Horde_Imap_Client_Exception_NoSupportExtension( - 'THREAD', - sprintf('Server does not support "%s" thread sort.', $tsort) - ); - } - } - - $cmd = $this->_command( - empty($options['sequence']) ? 'UID THREAD' : 'THREAD' - )->add($tsort); - - /* If UTF-8 support is activated, a client MUST send the UTF-8 - * charset specification since charset is mandatory for this - * command (RFC 6855 [3]; Errata 4029). */ - if (empty($options['search'])) { - if (!$this->_capability()->isEnabled('UTF8=ACCEPT')) { - $cmd->add('US-ASCII'); - } else { - $cmd->add('UTF-8'); - } - $cmd->add('ALL'); - } else { - $search_query = $options['search']->build(); - if (!$this->_capability()->isEnabled('UTF8=ACCEPT')) { - $cmd->add(is_null($search_query['charset']) ? 'US-ASCII' : $search_query['charset']); - } - $cmd->add($search_query['query'], true); - } - - return new Horde_Imap_Client_Data_Thread( - $this->_sendCmd($cmd)->data['threadparse'], - empty($options['sequence']) ? 'uid' : 'sequence' - ); - } - - /** - * Parse a THREAD response (RFC 5256 [4]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data Thread data. - */ - protected function _parseThread( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - $out = array(); - - while ($data->next() !== false) { - $thread = array(); - $this->_parseThreadLevel($thread, $data); - $out[] = $thread; - } - - $pipeline->data['threadparse'] = $out; - } - - /** - * Parse a level of a THREAD response (RFC 5256 [4]). - * - * @param array $thread Results. - * @param Horde_Imap_Client_Tokenize $data Thread data. - * @param integer $level The current tree level. - */ - protected function _parseThreadLevel(&$thread, - Horde_Imap_Client_Tokenize $data, - $level = 0) - { - while (($curr = $data->next()) !== false) { - if ($curr === true) { - $this->_parseThreadLevel($thread, $data, $level); - } elseif (!is_bool($curr)) { - $thread[$curr] = $level++; - } - } - } - - /** - */ - protected function _fetch(Horde_Imap_Client_Fetch_Results $results, - $queries) - { - $pipeline = $this->_pipeline(); - $pipeline->data['fetch_lookup'] = array(); - $pipeline->data['fetch_followup'] = array(); - - foreach ($queries as $options) { - $this->_fetchCmd($pipeline, $options); - $sequence = $options['ids']->sequence; - } - - try { - $resp = $this->_sendCmd($pipeline); - - /* Check for EXPUNGEISSUED (RFC 2180 [4.1]/RFC 5530 [3]). */ - if (!empty($resp->data['expungeissued'])) { - $this->noop(); - } - - foreach ($resp->fetch as $k => $v) { - $results->get($sequence ? $k : $v->getUid())->merge($v); - } - } catch (Horde_Imap_Client_Exception_ServerResponse $e) { - if ($e->status === Horde_Imap_Client_Interaction_Server::NO) { - if ($e->getCode() === $e::UNKNOWNCTE || - $e->getCode() === $e::PARSEERROR) { - /* UNKNOWN-CTE error. Redo the query without the BINARY - * elements. Also include PARSEERROR in this as - * Dovecot >= 2.2 binary fetch treats broken email as PARSE - * error and no longer UNKNOWN-CTE - */ - if (!empty($pipeline->data['binaryquery'])) { - foreach ($queries as $val) { - foreach ($pipeline->data['binaryquery'] as $key2 => $val2) { - unset($val2['decode']); - $val['_query']->bodyPart($key2, $val2); - $val['_query']->remove(Horde_Imap_Client::FETCH_BODYPARTSIZE, $key2); - } - $pipeline->data['fetch_followup'][] = $val; - } - } else { - $this->noop(); - } - } elseif ($sequence) { - /* A NO response, when coupled with a sequence FETCH, most - * likely means that messages were expunged. (RFC 2180 - * [4.1]) */ - $this->noop(); - } - } - } catch (Exception $e) { - // For any other error, ignore the Exception - fetch() is nice in - // that the return value explicitly handles missing data for any - // given message. - } - - if (!empty($pipeline->data['fetch_followup'])) { - $this->_fetch($results, $pipeline->data['fetch_followup']); - } - } - - /** - * Add a FETCH command to the given pipeline. - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param array $options Fetch query - * options - */ - protected function _fetchCmd( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - $options - ) - { - $fetch = new Horde_Imap_Client_Data_Format_List(); - $sequence = $options['ids']->sequence; - - /* Build an IMAP4rev1 compliant FETCH query. We handle the following - * criteria: - * BINARY[.PEEK][
]<> (RFC 3516) - * see BODY[] response - * BINARY.SIZE[
] (RFC 3516) - * BODY[.PEEK][
]<> - *
= HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, - * TEXT, empty - * <> = 0.# (# of bytes) - * BODYSTRUCTURE - * ENVELOPE - * FLAGS - * INTERNALDATE - * MODSEQ (RFC 7162) - * RFC822.SIZE - * UID - * - * No need to support these (can be built from other queries): - * =========================================================== - * ALL macro => (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE) - * BODY => Use BODYSTRUCTURE instead - * FAST macro => (FLAGS INTERNALDATE RFC822.SIZE) - * FULL macro => (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY) - * RFC822 => BODY[] - * RFC822.HEADER => BODY[HEADER] - * RFC822.TEXT => BODY[TEXT] - */ - - foreach ($options['_query'] as $type => $c_val) { - switch ($type) { - case Horde_Imap_Client::FETCH_STRUCTURE: - $fetch->add('BODYSTRUCTURE'); - break; - - case Horde_Imap_Client::FETCH_FULLMSG: - if (empty($c_val['peek'])) { - $this->openMailbox($this->_selected, Horde_Imap_Client::OPEN_READWRITE); - } - $fetch->add( - 'BODY' . - (!empty($c_val['peek']) ? '.PEEK' : '') . - '[]' . - $this->_partialAtom($c_val) - ); - break; - - case Horde_Imap_Client::FETCH_HEADERTEXT: - case Horde_Imap_Client::FETCH_BODYTEXT: - case Horde_Imap_Client::FETCH_MIMEHEADER: - case Horde_Imap_Client::FETCH_BODYPART: - case Horde_Imap_Client::FETCH_HEADERS: - foreach ($c_val as $key => $val) { - $cmd = ((int)$key == 0) - ? '' - : $key . '.'; - $main_cmd = 'BODY'; - - switch ($type) { - case Horde_Imap_Client::FETCH_HEADERTEXT: - $cmd .= 'HEADER'; - break; - - case Horde_Imap_Client::FETCH_BODYTEXT: - $cmd .= 'TEXT'; - break; - - case Horde_Imap_Client::FETCH_MIMEHEADER: - $cmd .= 'MIME'; - break; - - case Horde_Imap_Client::FETCH_BODYPART: - // Remove the last dot from the string. - $cmd = substr($cmd, 0, -1); - - if (!empty($val['decode']) && - $this->_capability('BINARY')) { - $main_cmd = 'BINARY'; - $pipeline->data['binaryquery'][$key] = $val; - } - break; - - case Horde_Imap_Client::FETCH_HEADERS: - $cmd .= 'HEADER.FIELDS'; - if (!empty($val['notsearch'])) { - $cmd .= '.NOT'; - } - $cmd .= ' (' . implode(' ', array_map('Horde_String::upper', $val['headers'])) . ')'; - - // Maintain a command -> label lookup so we can put - // the results in the proper location. - $pipeline->data['fetch_lookup'][$cmd] = $key; - } - - if (empty($val['peek'])) { - $this->openMailbox($this->_selected, Horde_Imap_Client::OPEN_READWRITE); - } - - $fetch->add( - $main_cmd . - (!empty($val['peek']) ? '.PEEK' : '') . - '[' . $cmd . ']' . - $this->_partialAtom($val) - ); - } - break; - - case Horde_Imap_Client::FETCH_BODYPARTSIZE: - if ($this->_capability('BINARY')) { - foreach ($c_val as $val) { - $fetch->add('BINARY.SIZE[' . $val . ']'); - } - } - break; - - case Horde_Imap_Client::FETCH_ENVELOPE: - $fetch->add('ENVELOPE'); - break; - - case Horde_Imap_Client::FETCH_FLAGS: - $fetch->add('FLAGS'); - break; - - case Horde_Imap_Client::FETCH_IMAPDATE: - $fetch->add('INTERNALDATE'); - break; - - case Horde_Imap_Client::FETCH_SIZE: - $fetch->add('RFC822.SIZE'); - break; - - case Horde_Imap_Client::FETCH_UID: - /* A UID FETCH will always return UID information (RFC 3501 - * [6.4.8]). Don't add to query as it just creates a longer - * FETCH command. */ - if ($sequence) { - $fetch->add('UID'); - } - break; - - case Horde_Imap_Client::FETCH_SEQ: - /* Nothing we need to add to fetch request unless sequence is - * the only criteria (see below). */ - break; - - case Horde_Imap_Client::FETCH_MODSEQ: - /* The 'changedsince' modifier implicitly adds the MODSEQ - * FETCH item (RFC 7162 [3.1.4.1]). Don't add to query as it - * just creates a longer FETCH command. */ - if (empty($options['changedsince'])) { - $fetch->add('MODSEQ'); - } - break; - } - } - - /* If empty fetch, add UID to make command valid. */ - if (!count($fetch)) { - $fetch->add('UID'); - } - - /* Add changedsince parameters. */ - if (empty($options['changedsince'])) { - $fetch_cmd = $fetch; - } else { - /* We might just want the list of UIDs changed since a given - * modseq. In that case, we don't have any other FETCH attributes, - * but RFC 3501 requires at least one specified attribute. */ - $fetch_cmd = array( - $fetch, - new Horde_Imap_Client_Data_Format_List(array( - 'CHANGEDSINCE', - new Horde_Imap_Client_Data_Format_Number($options['changedsince']) - )) - ); - } - - /* The FETCH command should be the only command issued by this library - * that should ever approach the command length limit. - * @todo Move this check to a more centralized location (_command()?). - * For simplification, assume that the UID list is the limiting factor - * and split this list at a sequence comma delimiter if it exceeds - * the character limit. */ - foreach ($options['ids']->split($this->_capability()->cmdlength) as $val) { - $cmd = $this->_command( - $sequence ? 'FETCH' : 'UID FETCH' - )->add(array( - $val, - $fetch_cmd - )); - $pipeline->add($cmd); - } - } - - /** - * Add a partial atom to an IMAP command based on the criteria options. - * - * @param array $opts Criteria options. - * - * @return string The partial atom. - */ - protected function _partialAtom($opts) - { - if (!empty($opts['length'])) { - return '<' . (empty($opts['start']) ? 0 : intval($opts['start'])) . '.' . intval($opts['length']) . '>'; - } - - return empty($opts['start']) - ? '' - : ('<' . intval($opts['start']) . '>'); - } - - /** - * Parse a FETCH response (RFC 3501 [7.4.2]). A FETCH response may occur - * due to a FETCH command, or due to a change in a message's state (i.e. - * the flags change). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param integer $id The message sequence number. - * @param Horde_Imap_Client_Tokenize $data The server response. - */ - protected function _parseFetch( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - $id, - Horde_Imap_Client_Tokenize $data - ) - { - if ($data->next() !== true) { - return; - } - - $ob = $pipeline->fetch->get($id); - $ob->setSeq($id); - - $flags = $modseq = $uid = false; - - while (($tag = $data->next()) !== false) { - $tag = Horde_String::upper($tag); - - /* Catch equivalent RFC822 tags, in case server returns them - * (in error, since we only use BODY in FETCH requests). */ - switch ($tag) { - case 'RFC822': - $tag = 'BODY[]'; - break; - - case 'RFC822.HEADER': - $tag = 'BODY[HEADER]'; - break; - - case 'RFC822.TEXT': - $tag = 'BODY[TEXT]'; - break; - } - - switch ($tag) { - case 'BODYSTRUCTURE': - $data->next(); - $structure = $this->_parseBodystructure($data); - $structure->buildMimeIds(); - $ob->setStructure($structure); - break; - - case 'ENVELOPE': - $data->next(); - $ob->setEnvelope($this->_parseEnvelope($data)); - break; - - case 'FLAGS': - $data->next(); - $ob->setFlags($data->flushIterator()); - $flags = true; - break; - - case 'INTERNALDATE': - $ob->setImapDate($data->next()); - break; - - case 'RFC822.SIZE': - $ob->setSize($data->next()); - break; - - case 'UID': - $ob->setUid($data->next()); - $uid = true; - break; - - case 'MODSEQ': - $data->next(); - $modseq = $data->next(); - $data->next(); - - /* MODSEQ must be greater than 0, so do sanity checking. */ - if ($modseq > 0) { - $ob->setModSeq($modseq); - - /* Store MODSEQ value. It may be used as the highestmodseq - * once a tagged response is received (RFC 7162 [6]). */ - $pipeline->data['modseqs'][] = $modseq; - } - break; - - default: - // Catch BODY[*]<#> responses - if (strpos($tag, 'BODY[') === 0) { - // Remove the beginning 'BODY[' - $tag = substr($tag, 5); - - // BODY[HEADER.FIELDS] request - if (!empty($pipeline->data['fetch_lookup']) && - (strpos($tag, 'HEADER.FIELDS') !== false)) { - $data->next(); - $sig = $tag . ' (' . implode(' ', array_map('Horde_String::upper', $data->flushIterator())) . ')'; - - // Ignore the trailing bracket - $data->next(); - - $ob->setHeaders($pipeline->data['fetch_lookup'][$sig], $data->next()); - } else { - // Remove trailing bracket and octet start info - $tag = substr($tag, 0, strrpos($tag, ']')); - - if (!strlen($tag)) { - // BODY[] request - if (!is_null($tmp = $data->nextStream())) { - $ob->setFullMsg($tmp); - } - } elseif (is_numeric(substr($tag, -1))) { - // BODY[MIMEID] request - if (!is_null($tmp = $data->nextStream())) { - $ob->setBodyPart($tag, $tmp); - } - } else { - // BODY[HEADER|TEXT|MIME] request - if (($last_dot = strrpos($tag, '.')) === false) { - $mime_id = 0; - } else { - $mime_id = substr($tag, 0, $last_dot); - $tag = substr($tag, $last_dot + 1); - } - - if (!is_null($tmp = $data->nextStream())) { - switch ($tag) { - case 'HEADER': - $ob->setHeaderText($mime_id, $tmp); - break; - - case 'TEXT': - $ob->setBodyText($mime_id, $tmp); - break; - - case 'MIME': - $ob->setMimeHeader($mime_id, $tmp); - break; - } - } - } - } - } elseif (strpos($tag, 'BINARY[') === 0) { - // Catch BINARY[*]<#> responses - // Remove the beginning 'BINARY[' and the trailing bracket - // and octet start info - $tag = substr($tag, 7, strrpos($tag, ']') - 7); - $body = $data->nextStream(); - - if (is_null($body)) { - /* Dovecot bug (as of 2.2.12): binary fetch of body - * part may fail with NIL return if decoding failed on - * server. Try again with non-decoded body. */ - $bq = $pipeline->data['binaryquery'][$tag]; - unset($bq['decode']); - - $query = new Horde_Imap_Client_Fetch_Query(); - $query->bodyPart($tag, $bq); - - $qids = ($quid = $ob->getUid()) - ? new Horde_Imap_Client_Ids($quid) - : new Horde_Imap_Client_Ids($id, true); - - $pipeline->data['fetch_followup'][] = array( - '_query' => $query, - 'ids' => $qids - ); - } else { - $ob->setBodyPart( - $tag, - $body, - empty($this->_temp['literal8']) ? '8bit' : 'binary' - ); - } - } elseif (strpos($tag, 'BINARY.SIZE[') === 0) { - // Catch BINARY.SIZE[*] responses - // Remove the beginning 'BINARY.SIZE[' and the trailing - // bracket and octet start info - $tag = substr($tag, 12, strrpos($tag, ']') - 12); - $ob->setBodyPartSize($tag, $data->next()); - } - break; - } - } - - /* MODSEQ issue: Oh joy. Per RFC 5162 (see Errata #1807), FETCH FLAGS - * responses are NOT required to provide UID information, even if - * QRESYNC is explicitly enabled. Caveat: the FLAGS information - * returned during a SELECT/EXAMINE MUST contain UIDs so we are OK - * there. - * The good news: all decent IMAP servers (Cyrus, Dovecot) will always - * provide UID information, so this is not normally an issue. - * The bad news: spec-wise, this behavior cannot be 100% guaranteed. - * Compromise: We will watch for a FLAGS response with a MODSEQ and - * check if a UID exists also. If not, put the sequence number in a - * queue - it is possible the UID information may appear later in an - * untagged response. When the command is over, double check to make - * sure there are none of these MODSEQ/FLAGS that are still UID-less. - * In the (rare) event that there is, don't cache anything and - * immediately close the mailbox: flags will be correctly sync'd next - * mailbox open so we only lose a bit of caching efficiency. - * Otherwise, we could end up with an inconsistent cached state. - * This Errata has been fixed in 7162 [3.2.4]. */ - if ($flags && $modseq && !$uid) { - $pipeline->data['modseqs_nouid'][] = $id; - } - } - - /** - * 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) as $key => $val) { - $ob->setContentTypeParameter($key, $val); - } - } - } else { - $ob->setType($entry . '/' . $data->next()); - - if ($data->next() === true) { - foreach ($this->_parseStructureParams($data) 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)); - } - - $te = $data->next(); - $bytes = $data->next(); - - if (!is_null($te)) { - $ob->setTransferEncoding($te); - - /* Base64 transfer encoding is approx. 33% larger than - * original data size (RFC 2045 [6.8]). Return from - * BODYSTRUCTURE is the size of the ENCODED data (RFC 3501 - * [7.4.2]). */ - if (strcasecmp($te, 'base64') === 0) { - $bytes *= 0.75; - } - } - - $ob->setBytes($bytes); - - // 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) 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; - } - - /** - * Helper function to parse a parameters-like tokenized array. - * - * @param mixed $data Message data. Either a Horde_Imap_Client_Tokenize - * object or null. - * - * @return array The parameter array. - */ - protected function _parseStructureParams($data) - { - $params = array(); - - if (is_null($data)) { - return $params; - } - - while (($name = $data->next()) !== false) { - $params[Horde_String::lower($name)] = $data->next(); - } - - $cp = new Horde_Mime_Headers_ContentParam('Unused', $params); - - return $cp->params; - } - - /** - * Parse ENVELOPE data from a FETCH return (see RFC 3501 [7.4.2]). - * - * @param Horde_Imap_Client_Tokenize $data Data returned from the server. - * - * @return Horde_Imap_Client_Data_Envelope An envelope object. - */ - protected function _parseEnvelope(Horde_Imap_Client_Tokenize $data) - { - // 'route', the 2nd element, is deprecated by RFC 2822. - $addr_structure = array( - 0 => 'personal', - 2 => 'mailbox', - 3 => 'host' - ); - $env_data = array( - 0 => 'date', - 1 => 'subject', - 2 => 'from', - 3 => 'sender', - 4 => 'reply_to', - 5 => 'to', - 6 => 'cc', - 7 => 'bcc', - 8 => 'in_reply_to', - 9 => 'message_id' - ); - - $addr_ob = new Horde_Mail_Rfc822_Address(); - $env_addrs = $this->getParam('envelope_addrs'); - $env_str = $this->getParam('envelope_string'); - $key = 0; - $ret = new Horde_Imap_Client_Data_Envelope(); - - while (($val = $data->next()) !== false) { - if (!isset($env_data[$key]) || is_null($val)) { - ++$key; - continue; - } - - if (is_string($val)) { - // These entries are text fields. - $ret->{$env_data[$key]} = substr($val, 0, $env_str); - } else { - // These entries are address structures. - $group = null; - $key2 = 0; - $tmp = new Horde_Mail_Rfc822_List(); - - while ($data->next() !== false) { - $a_val = $data->flushIterator(); - - // RFC 3501 [7.4.2]: Group entry when host is NIL. - // Group end when mailbox is NIL; otherwise, this is - // mailbox name. - if (is_null($a_val[3])) { - if (is_null($a_val[2])) { - $group = null; - } else { - $group = new Horde_Mail_Rfc822_Group($a_val[2]); - $tmp->add($group); - } - } else { - $addr = clone $addr_ob; - - foreach ($addr_structure as $add_key => $add_val) { - if (!is_null($a_val[$add_key])) { - $addr->$add_val = $a_val[$add_key]; - } - } - - if ($group) { - $group->addresses->add($addr); - } else { - $tmp->add($addr); - } - } - - if (++$key2 >= $env_addrs) { - $data->flushIterator(false); - break; - } - } - - $ret->{$env_data[$key]} = $tmp; - } - - ++$key; - } - - return $ret; - } - - /** - */ - protected function _vanished($modseq, Horde_Imap_Client_Ids $ids) - { - $pipeline = $this->_pipeline( - $this->_command('UID FETCH')->add(array( - strval($ids), - 'UID', - new Horde_Imap_Client_Data_Format_List(array( - 'VANISHED', - 'CHANGEDSINCE', - new Horde_Imap_Client_Data_Format_Number($modseq) - )) - )) - ); - $pipeline->data['vanished'] = $this->getIdsOb(); - - return $this->_sendCmd($pipeline)->data['vanished']; - } - - /** - */ - protected function _store($options) - { - $pipeline = $this->_storeCmd($options); - $pipeline->data['modified'] = $this->getIdsOb(); - - try { - $resp = $this->_sendCmd($pipeline); - - /* Check for EXPUNGEISSUED (RFC 2180 [4.2]/RFC 5530 [3]). */ - if (!empty($resp->data['expungeissued'])) { - $this->noop(); - } - - return $resp->data['modified']; - } catch (Horde_Imap_Client_Exception_ServerResponse $e) { - /* A NO response, when coupled with a sequence STORE and - * non-SILENT behavior, most likely means that messages were - * expunged. RFC 2180 [4.2] */ - if (empty($pipeline->data['store_silent']) && - !empty($options['sequence']) && - ($e->status === Horde_Imap_Client_Interaction_Server::NO)) { - $this->noop(); - } - - return $pipeline->data['modified']; - } - } - - /** - * Create a store command. - * - * @param array $options See Horde_Imap_Client_Base#_store(). - * - * @return Horde_Imap_Client_Interaction_Pipeline Pipeline object. - */ - protected function _storeCmd($options) - { - $cmds = array(); - $silent = empty($options['unchangedsince']) - ? !($this->_debug->debug || $this->_initCache(true)) - : false; - - if (!empty($options['replace'])) { - $cmds[] = array( - 'FLAGS' . ($silent ? '.SILENT' : ''), - $options['replace'] - ); - } else { - foreach (array('add' => '+', 'remove' => '-') as $k => $v) { - if (!empty($options[$k])) { - $cmds[] = array( - $v . 'FLAGS' . ($silent ? '.SILENT' : ''), - $options[$k] - ); - } - } - } - - $pipeline = $this->_pipeline(); - $pipeline->data['store_silent'] = $silent; - - foreach ($cmds as $val) { - $cmd = $this->_command( - empty($options['sequence']) ? 'UID STORE' : 'STORE' - )->add(strval($options['ids'])); - if (!empty($options['unchangedsince'])) { - $cmd->add(new Horde_Imap_Client_Data_Format_List(array( - 'UNCHANGEDSINCE', - new Horde_Imap_Client_Data_Format_Number(intval($options['unchangedsince'])) - ))); - } - $cmd->add($val); - - $pipeline->add($cmd); - } - - return $pipeline; - } - - /** - */ - protected function _copy(Horde_Imap_Client_Mailbox $dest, $options) - { - /* Check for MOVE command (RFC 6851). */ - $move_cmd = (!empty($options['move']) && - $this->_capability('MOVE')); - - $cmd = $this->_pipeline( - $this->_command( - ($options['ids']->sequence ? '' : 'UID ') . ($move_cmd ? 'MOVE' : 'COPY') - )->add(array( - strval($options['ids']), - $this->_getMboxFormatOb($dest) - )) - ); - $cmd->data['copydest'] = $dest; - - // COPY returns no untagged information (RFC 3501 [6.4.7]) - try { - $resp = $this->_sendCmd($cmd); - } catch (Horde_Imap_Client_Exception $e) { - if (!empty($options['create']) && - !empty($e->resp_data['trycreate'])) { - $this->createMailbox($dest); - unset($options['create']); - return $this->_copy($dest, $options); - } - throw $e; - } - - // If moving, delete the old messages now. Short-circuit if nothing - // was moved. - if (!$move_cmd && - !empty($options['move']) && - (isset($resp->data['copyuid']) || - !$this->_capability('UIDPLUS'))) { - $this->expunge($this->_selected, array( - 'delete' => true, - 'ids' => $options['ids'] - )); - } - - return isset($resp->data['copyuid']) - ? $resp->data['copyuid'] - : true; - } - - /** - */ - protected function _setQuota(Horde_Imap_Client_Mailbox $root, $resources) - { - $limits = new Horde_Imap_Client_Data_Format_List(); - - foreach ($resources as $key => $val) { - $limits->add(array( - Horde_String::upper($key), - new Horde_Imap_Client_Data_Format_Number($val) - )); - } - - $this->_sendCmd( - $this->_command('SETQUOTA')->add(array( - $this->_getMboxFormatOb($root), - $limits - )) - ); - } - - /** - */ - protected function _getQuota(Horde_Imap_Client_Mailbox $root) - { - $pipeline = $this->_pipeline( - $this->_command('GETQUOTA')->add( - $this->_getMboxFormatOb($root) - ) - ); - $pipeline->data['quotaresp'] = array(); - - return reset($this->_sendCmd($pipeline)->data['quotaresp']); - } - - /** - * Parse a QUOTA response (RFC 2087 [5.1]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The server response. - */ - protected function _parseQuota( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - $c = &$pipeline->data['quotaresp']; - - $root = $data->next(); - $c[$root] = array(); - - $data->next(); - - while (($curr = $data->next()) !== false) { - $c[$root][Horde_String::lower($curr)] = array( - 'usage' => $data->next(), - 'limit' => $data->next() - ); - } - } - - /** - */ - protected function _getQuotaRoot(Horde_Imap_Client_Mailbox $mailbox) - { - $pipeline = $this->_pipeline( - $this->_command('GETQUOTAROOT')->add( - $this->_getMboxFormatOb($mailbox) - ) - ); - $pipeline->data['quotaresp'] = array(); - - return $this->_sendCmd($pipeline)->data['quotaresp']; - } - - /** - */ - protected function _setACL(Horde_Imap_Client_Mailbox $mailbox, $identifier, - $options) - { - // SETACL returns no untagged information (RFC 4314 [3.1]). - $this->_sendCmd( - $this->_command('SETACL')->add(array( - $this->_getMboxFormatOb($mailbox), - new Horde_Imap_Client_Data_Format_Astring($identifier), - new Horde_Imap_Client_Data_Format_Astring($options['rights']) - )) - ); - } - - /** - */ - protected function _deleteACL(Horde_Imap_Client_Mailbox $mailbox, $identifier) - { - // DELETEACL returns no untagged information (RFC 4314 [3.2]). - $this->_sendCmd( - $this->_command('DELETEACL')->add(array( - $this->_getMboxFormatOb($mailbox), - new Horde_Imap_Client_Data_Format_Astring($identifier) - )) - ); - } - - /** - */ - protected function _getACL(Horde_Imap_Client_Mailbox $mailbox) - { - return $this->_sendCmd( - $this->_command('GETACL')->add( - $this->_getMboxFormatOb($mailbox) - ) - )->data['getacl']; - } - - /** - * Parse an ACL response (RFC 4314 [3.6]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The server response. - */ - protected function _parseACL( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - $acl = array(); - - // Ignore mailbox argument -> index 1 - $data->next(); - - while (($curr = $data->next()) !== false) { - $acl[$curr] = ($curr[0] === '-') - ? new Horde_Imap_Client_Data_AclNegative($data->next()) - : new Horde_Imap_Client_Data_Acl($data->next()); - } - - $pipeline->data['getacl'] = $acl; - } - - /** - */ - protected function _listACLRights(Horde_Imap_Client_Mailbox $mailbox, - $identifier) - { - $resp = $this->_sendCmd( - $this->_command('LISTRIGHTS')->add(array( - $this->_getMboxFormatOb($mailbox), - new Horde_Imap_Client_Data_Format_Astring($identifier) - )) - ); - - return isset($resp->data['listaclrights']) - ? $resp->data['listaclrights'] - : new Horde_Imap_Client_Data_AclRights(); - } - - /** - * Parse a LISTRIGHTS response (RFC 4314 [3.7]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The server response. - */ - protected function _parseListRights( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - // Ignore mailbox and identifier arguments - $data->next(); - $data->next(); - - $pipeline->data['listaclrights'] = new Horde_Imap_Client_Data_AclRights( - str_split($data->next()), - $data->flushIterator() - ); - } - - /** - */ - protected function _getMyACLRights(Horde_Imap_Client_Mailbox $mailbox) - { - $resp = $this->_sendCmd( - $this->_command('MYRIGHTS')->add( - $this->_getMboxFormatOb($mailbox) - ) - ); - - return isset($resp->data['myrights']) - ? $resp->data['myrights'] - : new Horde_Imap_Client_Data_Acl(); - } - - /** - * Parse a MYRIGHTS response (RFC 4314 [3.8]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The server response. - */ - protected function _parseMyRights( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - // Ignore 1st token (mailbox name) - $data->next(); - - $pipeline->data['myrights'] = new Horde_Imap_Client_Data_Acl($data->next()); - } - - /** - */ - protected function _getMetadata(Horde_Imap_Client_Mailbox $mailbox, - $entries, $options) - { - $pipeline = $this->_pipeline(); - $pipeline->data['metadata'] = array(); - - if ($this->_capability('METADATA') || - (strlen($mailbox) && $this->_capability('METADATA-SERVER'))) { - $cmd_options = new Horde_Imap_Client_Data_Format_List(); - - if (!empty($options['maxsize'])) { - $cmd_options->add(array( - 'MAXSIZE', - new Horde_Imap_Client_Data_Format_Number($options['maxsize']) - )); - } - if (!empty($options['depth'])) { - $cmd_options->add(array( - 'DEPTH', - new Horde_Imap_Client_Data_Format_Number($options['depth']) - )); - } - - $queries = new Horde_Imap_Client_Data_Format_List(); - foreach ($entries as $md_entry) { - $queries->add(new Horde_Imap_Client_Data_Format_Astring($md_entry)); - } - - $cmd = $this->_command('GETMETADATA')->add( - $this->_getMboxFormatOb($mailbox) - ); - if (count($cmd_options)) { - $cmd->add($cmd_options); - } - $cmd->add($queries); - - $pipeline->add($cmd); - } else { - if (!$this->_capability('ANNOTATEMORE') && - !$this->_capability('ANNOTATEMORE2')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('METADATA'); - } - - $queries = array(); - foreach ($entries as $md_entry) { - list($entry, $type) = $this->_getAnnotateMoreEntry($md_entry); - - if (!isset($queries[$type])) { - $queries[$type] = new Horde_Imap_Client_Data_Format_List(); - } - $queries[$type]->add(new Horde_Imap_Client_Data_Format_String($entry)); - } - - foreach ($queries as $key => $val) { - // TODO: Honor maxsize and depth options. - $pipeline->add( - $this->_command('GETANNOTATION')->add(array( - $this->_getMboxFormatOb($mailbox), - $val, - new Horde_Imap_Client_Data_Format_String($key) - )) - ); - } - } - - return $this->_sendCmd($pipeline)->data['metadata']; - } - - /** - * Split a name for the METADATA extension into the correct syntax for the - * older ANNOTATEMORE version. - * - * @param string $name A name for a metadata entry. - * - * @return array A list of two elements: The entry name and the value - * type. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _getAnnotateMoreEntry($name) - { - if (substr($name, 0, 7) === '/shared') { - return array(substr($name, 7), 'value.shared'); - } else if (substr($name, 0, 8) === '/private') { - return array(substr($name, 8), 'value.priv'); - } - - $e = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Invalid METADATA entry: \"%s\"."), - Horde_Imap_Client_Exception::METADATA_INVALID - ); - $e->messagePrintf(array($name)); - throw $e; - } - - /** - */ - protected function _setMetadata(Horde_Imap_Client_Mailbox $mailbox, $data) - { - if ($this->_capability('METADATA') || - (strlen($mailbox) && $this->_capability('METADATA-SERVER'))) { - $data_elts = new Horde_Imap_Client_Data_Format_List(); - - foreach ($data as $key => $value) { - $data_elts->add(array( - new Horde_Imap_Client_Data_Format_Astring($key), - /* METADATA supports literal8 - thus, it implicitly - * supports non-ASCII characters in the data. */ - new Horde_Imap_Client_Data_Format_Nstring_Nonascii($value) - )); - } - - $cmd = $this->_command('SETMETADATA')->add(array( - $this->_getMboxFormatOb($mailbox), - $data_elts - )); - } else { - if (!$this->_capability('ANNOTATEMORE') && - !$this->_capability('ANNOTATEMORE2')) { - throw new Horde_Imap_Client_Exception_NoSupportExtension('METADATA'); - } - - $cmd = $this->_pipeline(); - - foreach ($data as $md_entry => $value) { - list($entry, $type) = $this->_getAnnotateMoreEntry($md_entry); - - $cmd->add( - $this->_command('SETANNOTATION')->add(array( - $this->_getMboxFormatOb($mailbox), - new Horde_Imap_Client_Data_Format_String($entry), - new Horde_Imap_Client_Data_Format_List(array( - new Horde_Imap_Client_Data_Format_String($type), - /* ANNOTATEMORE supports literal8 - thus, it - * implicitly supports non-ASCII characters in the - * data. */ - new Horde_Imap_Client_Data_Format_Nstring_Nonascii($value) - )) - )) - ); - } - } - - $this->_sendCmd($cmd); - } - - /** - * Parse an ANNOTATION response (ANNOTATEMORE/ANNOTATEMORE2). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The server response. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _parseAnnotation( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - // Mailbox name is in UTF7-IMAP. - $mbox = Horde_Imap_Client_Mailbox::get($data->next(), true); - $entry = $data->next(); - - // Ignore unsolicited responses. - if ($data->next() !== true) { - return; - } - - while (($type = $data->next()) !== false) { - switch ($type) { - case 'value.priv': - $pipeline->data['metadata'][strval($mbox)]['/private' . $entry] = $data->next(); - break; - - case 'value.shared': - $pipeline->data['metadata'][strval($mbox)]['/shared' . $entry] = $data->next(); - break; - - default: - $e = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Invalid METADATA value type \"%s\"."), - Horde_Imap_Client_Exception::METADATA_INVALID - ); - $e->messagePrintf(array($type)); - throw $e; - } - } - } - - /** - * Parse a METADATA response (RFC 5464 [4.4]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Tokenize $data The server response. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _parseMetadata( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Tokenize $data - ) - { - // Mailbox name is in UTF7-IMAP. - $mbox = Horde_Imap_Client_Mailbox::get($data->next(), true); - - // Ignore unsolicited responses. - if ($data->next() === true) { - while (($entry = $data->next()) !== false) { - $pipeline->data['metadata'][strval($mbox)][$entry] = $data->next(); - } - } - } - - /* Overriden methods. */ - - /** - * @param array $opts Options: - * - decrement: (boolean) If true, decrement the message count. - * - pipeline: (Horde_Imap_Client_Interaction_Pipeline) Pipeline object. - */ - protected function _deleteMsgs(Horde_Imap_Client_Mailbox $mailbox, - Horde_Imap_Client_Ids $ids, - array $opts = array()) - { - /* If there are pending FETCH cache writes, we need to write them - * before the UID -> sequence number mapping changes. */ - if (isset($opts['pipeline'])) { - $this->_updateCache($opts['pipeline']->fetch); - } - - $res = parent::_deleteMsgs($mailbox, $ids); - - if (isset($this->_temp['expunged'])) { - $this->_temp['expunged']->add($res); - } - - if (!empty($opts['decrement'])) { - $mbox_ob = $this->_mailboxOb(); - $mbox_ob->setStatus( - Horde_Imap_Client::STATUS_MESSAGES, - $mbox_ob->getStatus(Horde_Imap_Client::STATUS_MESSAGES) - count($ids) - ); - } - } - - /* Internal functions. */ - - /** - * Return the proper mailbox format object based on the server's - * capabilities. - * - * @param string $mailbox The mailbox. - * @param boolean $list Is this object used in a LIST command? - * - * @return Horde_Imap_Client_Data_Format_Mailbox A mailbox format object. - */ - protected function _getMboxFormatOb($mailbox, $list = false) - { - if ($this->_capability()->isEnabled('UTF8=ACCEPT')) { - try { - return $list - ? new Horde_Imap_Client_Data_Format_ListMailbox_Utf8($mailbox) - : new Horde_Imap_Client_Data_Format_Mailbox_Utf8($mailbox); - } catch (Horde_Imap_Client_Data_Format_Exception $e) {} - } - - return $list - ? new Horde_Imap_Client_Data_Format_ListMailbox($mailbox) - : new Horde_Imap_Client_Data_Format_Mailbox($mailbox); - } - - /** - * Sends command(s) to the IMAP server. A connection to the server must - * have already been made. - * - * @param mixed $cmd Either a Command object or a Pipeline object. - * - * @return Horde_Imap_Client_Interaction_Pipeline A pipeline object. - * @throws Horde_Imap_Client_Exception - */ - protected function _sendCmd($cmd) - { - $pipeline = ($cmd instanceof Horde_Imap_Client_Interaction_Command) - ? $this->_pipeline($cmd) - : $cmd; - - if (!empty($this->_cmdQueue)) { - /* Add commands in reverse order. */ - foreach (array_reverse($this->_cmdQueue) as $val) { - $pipeline->add($val, true); - } - - $this->_cmdQueue = array(); - } - - $cmd_list = array(); - - foreach ($pipeline as $val) { - if ($val->continuation) { - $this->_sendCmdChunk($pipeline, $cmd_list); - $this->_sendCmdChunk($pipeline, array($val)); - $cmd_list = array(); - } else { - $cmd_list[] = $val; - } - } - - $this->_sendCmdChunk($pipeline, $cmd_list); - - /* If any FLAGS responses contain MODSEQs but not UIDs, don't - * cache any data and immediately close the mailbox. */ - foreach ($pipeline->data['modseqs_nouid'] as $val) { - if (!$pipeline->fetch[$val]->getUid()) { - $this->_debug->info( - 'Server provided FLAGS MODSEQ without providing UID.' - ); - $this->close(); - return $pipeline; - } - } - - /* Update HIGHESTMODSEQ value. */ - if (!empty($pipeline->data['modseqs'])) { - $modseq = max($pipeline->data['modseqs']); - $this->_mailboxOb()->setStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ, $modseq); - /* CONDSTORE has not yet updated flag information, so don't update - * modseq yet. */ - if ($this->_capability()->isEnabled('QRESYNC')) { - $this->_updateModSeq($modseq); - } - } - - /* Update cache items. */ - $this->_updateCache($pipeline->fetch); - - return $pipeline; - } - - /** - * Send a chunk of commands and/or continuation fragments to the server. - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline The pipeline - * object. - * @param array $chunk List of commands to send. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _sendCmdChunk($pipeline, $chunk) - { - if (empty($chunk)) { - return; - } - - $cmd_count = count($chunk); - $exception = null; - - foreach ($chunk as $val) { - $val->pipeline = $pipeline; - - try { - if ($this->_processCmd($pipeline, $val, $val)) { - $this->_connection->write('', true); - } else { - $cmd_count = 0; - } - } catch (Horde_Imap_Client_Exception $e) { - switch ($e->getCode()) { - case Horde_Imap_Client_Exception::SERVER_WRITEERROR: - $this->_temp['logout'] = true; - $this->logout(); - break; - } - - throw $e; - } - } - - while ($cmd_count) { - try { - if ($this->_getLine($pipeline) instanceof Horde_Imap_Client_Interaction_Server_Tagged) { - --$cmd_count; - } - } catch (Horde_Imap_Client_Exception $e) { - switch ($e->getCode()) { - case $e::DISCONNECT: - /* Guaranteed to have no more data incoming, so we can - * immediately logout. */ - $this->_temp['logout'] = true; - $this->logout(); - throw $e; - } - - /* For all other issues, catch and store exception; don't - * throw until all input is read since we need to clear - * incoming queue. (For now, only store first exception.) */ - if (is_null($exception)) { - $exception = $e; - } - - if (($e instanceof Horde_Imap_Client_Exception_ServerResponse) && - $e->command) { - --$cmd_count; - } - } - } - - if (!is_null($exception)) { - throw $exception; - } - } - - /** - * Process/send a command to the remote server. - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline The pipeline - * object. - * @param Horde_Imap_Client_Interaction_Command $cmd The master command. - * @param Horde_Imap_Client_Data_Format_List $data Commands to send. - * - * @return boolean True if EOL needed to finish command. - * @throws Horde_Imap_Client_Exception - * @throws Horde_Imap_Client_Exception_NoSupport - */ - protected function _processCmd($pipeline, $cmd, $data) - { - if ($this->_debug->debug && - ($data instanceof Horde_Imap_Client_Interaction_Command)) { - $data->startTimer(); - } - - foreach ($data as $key => $val) { - if ($val instanceof Horde_Imap_Client_Interaction_Command_Continuation) { - $this->_connection->write('', true); - - /* Check for optional continuation responses when the command - * has already finished. */ - if (!$cmd_continuation = $this->_processCmdContinuation($pipeline, $val->optional)) { - return false; - } - - $this->_processCmd( - $pipeline, - $cmd, - $val->getCommands($cmd_continuation) - ); - continue; - } - - if (!is_null($debug_msg = array_shift($cmd->debug))) { - $this->_debug->client( - (($cmd == $data) ? $cmd->tag . ' ' : '') . $debug_msg - ); - $this->_connection->client_debug = false; - } - - if ($key) { - $this->_connection->write(' '); - } - - if ($val instanceof Horde_Imap_Client_Data_Format_List) { - $this->_connection->write('('); - $this->_processCmd($pipeline, $cmd, $val); - $this->_connection->write(')'); - } elseif (($val instanceof Horde_Imap_Client_Data_Format_String) && - $val->literal()) { - $c = $this->_capability(); - - /* RFC 6855: If UTF8 extension is available, quote short - * strings instead of sending as literal. */ - if ($c->isEnabled('UTF8=ACCEPT') && ($val->length() < 100)) { - $val->forceQuoted(); - $this->_connection->write($val->escape()); - } else { - /* RFC 3516/4466: Send literal8 if we have binary data. */ - if ($cmd->literal8 && - $val->binary() && - ($c->query('BINARY') || $c->isEnabled('UTF8=ACCEPT'))) { - $binary = true; - $this->_connection->write('~'); - } else { - $binary = false; - } - - $literal_len = $val->length(); - $this->_connection->write('{' . $literal_len); - - /* RFC 2088 - If LITERAL+ is available, saves a roundtrip - * from the server. */ - if ($cmd->literalplus && $c->query('LITERAL+')) { - $this->_connection->write('+}', true); - } else { - $this->_connection->write('}', true); - $this->_processCmdContinuation($pipeline); - } - - if ($debug_msg) { - $this->_connection->client_debug = false; - } - - $this->_connection->writeLiteral( - $val->getStream(), - $literal_len, - $binary - ); - } - } else { - $this->_connection->write($val->escape()); - } - } - - return true; - } - - /** - * Process a command continuation response. - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline The pipeline - * object. - * @param boolean $noexception Don't throw - * exception if - * continuation - * does not occur. - * - * @return mixed A Horde_Imap_Client_Interaction_Server_Continuation - * object or false. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _processCmdContinuation($pipeline, $noexception = false) - { - do { - $ob = $this->_getLine($pipeline); - } while ($ob instanceof Horde_Imap_Client_Interaction_Server_Untagged); - - if ($ob instanceof Horde_Imap_Client_Interaction_Server_Continuation) { - return $ob; - } elseif ($noexception) { - return false; - } - - $this->_debug->info( - 'ERROR: Unexpected response from server while waiting for a continuation request.' - ); - $e = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error when communicating with the mail server."), - Horde_Imap_Client_Exception::SERVER_READERROR - ); - $e->details = strval($ob); - - throw $e; - } - - /** - * Shortcut to creating a new IMAP client command object. - * - * @param string $cmd The IMAP command. - * - * @return Horde_Imap_Client_Interaction_Command A command object. - */ - protected function _command($cmd) - { - return new Horde_Imap_Client_Interaction_Command($cmd, ++$this->_tag); - } - - /** - * Shortcut to creating a new pipeline object. - * - * @param Horde_Imap_Client_Interaction_Command $cmd An IMAP command to - * add. - * - * @return Horde_Imap_Client_Interaction_Pipeline A pipeline object. - */ - protected function _pipeline($cmd = null) - { - if (!isset($this->_temp['fetchob'])) { - $this->_temp['fetchob'] = new Horde_Imap_Client_Fetch_Results( - $this->_fetchDataClass, - Horde_Imap_Client_Fetch_Results::SEQUENCE - ); - } - - $ob = new Horde_Imap_Client_Interaction_Pipeline( - clone $this->_temp['fetchob'] - ); - - if (!is_null($cmd)) { - $ob->add($cmd); - } - - return $ob; - } - - /** - * Gets data from the IMAP server stream and parses it. - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * - * @return Horde_Imap_Client_Interaction_Server Server object. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _getLine( - Horde_Imap_Client_Interaction_Pipeline $pipeline - ) - { - $server = Horde_Imap_Client_Interaction_Server::create( - $this->_connection->read() - ); - - switch (get_class($server)) { - case 'Horde_Imap_Client_Interaction_Server_Continuation': - $this->_responseCode($pipeline, $server); - break; - - case 'Horde_Imap_Client_Interaction_Server_Tagged': - $cmd = $pipeline->complete($server); - if (is_null($cmd)) { - /* This indicates a "dangling" tagged response - it was either - * generated by an aborted previous pipeline object or is the - * result of spurious output by the server. Ignore. */ - return $this->_getLine($pipeline); - } - - if ($timer = $cmd->getTimer()) { - $this->_debug->info(sprintf( - 'Command %s took %s seconds.', - $cmd->tag, - $timer - )); - } - $this->_responseCode($pipeline, $server); - - if (is_callable($cmd->on_success)) { - call_user_func($cmd->on_success); - } - break; - - case 'Horde_Imap_Client_Interaction_Server_Untagged': - if (is_null($server->status)) { - $this->_serverResponse($pipeline, $server); - } else { - $this->_responseCode($pipeline, $server); - } - break; - } - - switch ($server->status) { - case $server::BAD: - case $server::NO: - /* A tagged BAD response indicates that the tagged command caused - * the error. This information is unknown if untagged (RFC 3501 - * [7.1.3]) - ignore these untagged responses. - * An untagged NO response indicates a warning; ignore and assume - * that it also included response text code that is handled - * elsewhere. Throw exception if tagged; command handlers can - * catch this if able to workaround this issue (RFC 3501 - * [7.1.2]). */ - if ($server instanceof Horde_Imap_Client_Interaction_Server_Tagged) { - /* Check for a on_error callback. If function returns true, - * ignore the error. */ - if (($cmd = $pipeline->getCmd($server->tag)) && - is_callable($cmd->on_error) && - call_user_func($cmd->on_error)) { - break; - } - - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("IMAP error reported by server."), - 0, - $server, - $pipeline - ); - } - break; - - case $server::BYE: - /* A BYE response received as part of a logout command should be - * be treated like a regular command: a client MUST process the - * entire command until logging out (RFC 3501 [3.4; 7.1.5]). */ - if (empty($this->_temp['logout'])) { - $e = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("IMAP Server closed the connection."), - Horde_Imap_Client_Exception::DISCONNECT - ); - $e->details = strval($server); - throw $e; - } - break; - - case $server::PREAUTH: - /* The user was pre-authenticated. (RFC 3501 [7.1.4]) */ - $this->_temp['preauth'] = true; - break; - } - - return $server; - } - - /** - * Handle untagged server responses (see RFC 3501 [2.2.2]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Interaction_Server $ob Server - * response. - */ - protected function _serverResponse( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Interaction_Server $ob - ) - { - $token = $ob->token; - - /* First, catch untagged responses where the name appears first on the - * line. */ - switch ($first = Horde_String::upper($token->current())) { - case 'CAPABILITY': - $this->_parseCapability($pipeline, $token->flushIterator()); - break; - - case 'LIST': - case 'LSUB': - $this->_parseList($pipeline, $token); - break; - - case 'STATUS': - // Parse a STATUS response (RFC 3501 [7.2.4]). - $this->_parseStatus($token); - break; - - case 'SEARCH': - case 'SORT': - // Parse a SEARCH/SORT response (RFC 3501 [7.2.5] & RFC 5256 [4]). - $this->_parseSearch($pipeline, $token->flushIterator()); - break; - - case 'ESEARCH': - // Parse an ESEARCH response (RFC 4466 [2.6.2]). - $this->_parseEsearch($pipeline, $token); - break; - - case 'FLAGS': - $token->next(); - $this->_mailboxOb()->setStatus(Horde_Imap_Client::STATUS_FLAGS, array_map('Horde_String::lower', $token->flushIterator())); - break; - - case 'QUOTA': - $this->_parseQuota($pipeline, $token); - break; - - case 'QUOTAROOT': - // Ignore this line - we can get this information from - // the untagged QUOTA responses. - break; - - case 'NAMESPACE': - $this->_parseNamespace($pipeline, $token); - break; - - case 'THREAD': - $this->_parseThread($pipeline, $token); - break; - - case 'ACL': - $this->_parseACL($pipeline, $token); - break; - - case 'LISTRIGHTS': - $this->_parseListRights($pipeline, $token); - break; - - case 'MYRIGHTS': - $this->_parseMyRights($pipeline, $token); - break; - - case 'ID': - // ID extension (RFC 2971) - $this->_parseID($pipeline, $token); - break; - - case 'ENABLED': - // ENABLE extension (RFC 5161) - $this->_parseEnabled($token); - break; - - case 'LANGUAGE': - // LANGUAGE extension (RFC 5255 [3.2]) - $this->_parseLanguage($token); - break; - - case 'COMPARATOR': - // I18NLEVEL=2 extension (RFC 5255 [4.7]) - $this->_parseComparator($pipeline, $token); - break; - - case 'VANISHED': - // QRESYNC extension (RFC 7162 [3.2.10]) - $this->_parseVanished($pipeline, $token); - break; - - case 'ANNOTATION': - // Parse an ANNOTATION response. - $this->_parseAnnotation($pipeline, $token); - break; - - case 'METADATA': - // Parse a METADATA response. - $this->_parseMetadata($pipeline, $token); - break; - - default: - // Next, look for responses where the keywords occur second. - switch (Horde_String::upper($token->next())) { - case 'EXISTS': - // EXISTS response - RFC 3501 [7.3.2] - $mbox_ob = $this->_mailboxOb(); - - // Increment UIDNEXT if it is set. - if ($mbox_ob->open && - ($uidnext = $mbox_ob->getStatus(Horde_Imap_Client::STATUS_UIDNEXT))) { - $mbox_ob->setStatus(Horde_Imap_Client::STATUS_UIDNEXT, $uidnext + $first - $mbox_ob->getStatus(Horde_Imap_Client::STATUS_MESSAGES)); - } - - $mbox_ob->setStatus(Horde_Imap_Client::STATUS_MESSAGES, $first); - break; - - case 'RECENT': - // RECENT response - RFC 3501 [7.3.1] - $this->_mailboxOb()->setStatus(Horde_Imap_Client::STATUS_RECENT, $first); - break; - - case 'EXPUNGE': - // EXPUNGE response - RFC 3501 [7.4.1] - $this->_deleteMsgs($this->_selected, $this->getIdsOb($first, true), array( - 'decrement' => true, - 'pipeline' => $pipeline - )); - $pipeline->data['expunge_seen'] = true; - break; - - case 'FETCH': - // FETCH response - RFC 3501 [7.4.2] - $this->_parseFetch($pipeline, $first, $token); - break; - } - break; - } - } - - /** - * Handle status responses (see RFC 3501 [7.1]). - * - * @param Horde_Imap_Client_Interaction_Pipeline $pipeline Pipeline - * object. - * @param Horde_Imap_Client_Interaction_Server $ob Server object. - * - * @throws Horde_Imap_Client_Exception_ServerResponse - */ - protected function _responseCode( - Horde_Imap_Client_Interaction_Pipeline $pipeline, - Horde_Imap_Client_Interaction_Server $ob - ) - { - if (is_null($ob->responseCode)) { - return; - } - - $rc = $ob->responseCode; - - switch ($rc->code) { - case 'ALERT': - // Defined by RFC 5530 [3] - Treat as an alert for now. - case 'CONTACTADMIN': - // Used by Gmail - Treat as an alert for now. - // http://mailman13.u.washington.edu/pipermail/imap-protocol/2014-September/002324.html - case 'WEBALERT': - $this->_alerts->add(strval($ob->token), $rc->code); - break; - - case 'BADCHARSET': - /* Store valid search charsets if returned by server. */ - $s = $this->search_charset; - foreach ($rc->data[0] as $val) { - $s->setValid($val, true); - } - - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("Charset used in search query is not supported on the mail server."), - Horde_Imap_Client_Exception::BADCHARSET, - $ob, - $pipeline - ); - - case 'CAPABILITY': - $this->_parseCapability($pipeline, $rc->data); - break; - - case 'PARSE': - /* Only throw error on NO/BAD. Message is human readable. */ - switch ($ob->status) { - case Horde_Imap_Client_Interaction_Server::BAD: - case Horde_Imap_Client_Interaction_Server::NO: - $e = new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The mail server was unable to parse the contents of the mail message: %s"), - Horde_Imap_Client_Exception::PARSEERROR, - $ob, - $pipeline - ); - $e->messagePrintf(array(strval($ob->token))); - throw $e; - } - break; - - case 'READ-ONLY': - $this->_mode = Horde_Imap_Client::OPEN_READONLY; - break; - - case 'READ-WRITE': - $this->_mode = Horde_Imap_Client::OPEN_READWRITE; - break; - - case 'TRYCREATE': - // RFC 3501 [7.1] - $pipeline->data['trycreate'] = true; - break; - - case 'PERMANENTFLAGS': - $this->_mailboxOb()->setStatus(Horde_Imap_Client::STATUS_PERMFLAGS, array_map('Horde_String::lower', $rc->data[0])); - break; - - case 'UIDNEXT': - $this->_mailboxOb()->setStatus(Horde_Imap_Client::STATUS_UIDNEXT, $rc->data[0]); - break; - - case 'UIDVALIDITY': - $this->_mailboxOb()->setStatus(Horde_Imap_Client::STATUS_UIDVALIDITY, $rc->data[0]); - break; - - case 'UNSEEN': - /* This is different from the STATUS UNSEEN response - this item, - * if defined, returns the first UNSEEN message in the mailbox. */ - $this->_mailboxOb()->setStatus(Horde_Imap_Client::STATUS_FIRSTUNSEEN, $rc->data[0]); - break; - - case 'REFERRAL': - // Defined by RFC 2221 - $pipeline->data['referral'] = new Horde_Imap_Client_Url_Imap($rc->data[0]); - break; - - case 'UNKNOWN-CTE': - // Defined by RFC 3516 - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The mail server was unable to parse the contents of the mail message."), - Horde_Imap_Client_Exception::UNKNOWNCTE, - $ob, - $pipeline - ); - - case 'APPENDUID': - // Defined by RFC 4315 - // APPENDUID: [0] = UIDVALIDITY, [1] = UID(s) - $pipeline->data['appenduid'] = $this->getIdsOb($rc->data[1]); - break; - - case 'COPYUID': - // Defined by RFC 4315 - // COPYUID: [0] = UIDVALIDITY, [1] = UIDFROM, [2] = UIDTO - $pipeline->data['copyuid'] = array_combine( - $this->getIdsOb($rc->data[1])->ids, - $this->getIdsOb($rc->data[2])->ids - ); - - /* Use UIDPLUS information to move cached data to new mailbox (see - * RFC 4549 [4.2.2.1]). Need to move now, because a MOVE might - * EXPUNGE immediately afterwards. */ - $this->_moveCache($pipeline->data['copydest'], $pipeline->data['copyuid'], $rc->data[0]); - break; - - case 'UIDNOTSTICKY': - // Defined by RFC 4315 [3] - $this->_mailboxOb()->setStatus(Horde_Imap_Client::STATUS_UIDNOTSTICKY, true); - break; - - case 'BADURL': - // Defined by RFC 4469 [4.1] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("Could not save message on server."), - Horde_Imap_Client_Exception::CATENATE_BADURL, - $ob, - $pipeline - ); - - case 'TOOBIG': - // Defined by RFC 4469 [4.2] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("Could not save message data because it is too large."), - Horde_Imap_Client_Exception::CATENATE_TOOBIG, - $ob, - $pipeline - ); - - case 'HIGHESTMODSEQ': - // Defined by RFC 7162 [3.1.2.1] - $pipeline->data['modseqs'][] = $rc->data[0]; - break; - - case 'NOMODSEQ': - // Defined by RFC 7162 [3.1.2.2] - $pipeline->data['modseqs'][] = 0; - break; - - case 'MODIFIED': - // Defined by RFC 7162 [3.1.3] - $pipeline->data['modified']->add($rc->data[0]); - break; - - case 'CLOSED': - // Defined by RFC 7162 [3.2.11] - if (isset($pipeline->data['qresyncmbox'])) { - /* If there is any pending FETCH cache entries, flush them - * now before changing mailboxes. */ - $this->_updateCache($pipeline->fetch); - $pipeline->fetch->clear(); - - $this->_changeSelected( - $pipeline->data['qresyncmbox'][0], - $pipeline->data['qresyncmbox'][1] - ); - unset($pipeline->data['qresyncmbox']); - } - break; - - case 'NOTSAVED': - // Defined by RFC 5182 [2.5] - $pipeline->data['searchnotsaved'] = true; - break; - - case 'BADCOMPARATOR': - // Defined by RFC 5255 [4.9] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The comparison algorithm was not recognized by the server."), - Horde_Imap_Client_Exception::BADCOMPARATOR, - $ob, - $pipeline - ); - - case 'METADATA': - $md = $rc->data[0]; - - switch ($md[0]) { - case 'LONGENTRIES': - // Defined by RFC 5464 [4.2.1] - $pipeline->data['metadata']['*longentries'] = intval($md[1]); - break; - - case 'MAXSIZE': - // Defined by RFC 5464 [4.3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The metadata item could not be saved because it is too large."), - Horde_Imap_Client_Exception::METADATA_MAXSIZE, - $ob, - $pipeline - ); - - case 'NOPRIVATE': - // Defined by RFC 5464 [4.3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The metadata item could not be saved because the server does not support private annotations."), - Horde_Imap_Client_Exception::METADATA_NOPRIVATE, - $ob, - $pipeline - ); - - case 'TOOMANY': - // Defined by RFC 5464 [4.3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The metadata item could not be saved because the maximum number of annotations has been exceeded."), - Horde_Imap_Client_Exception::METADATA_TOOMANY, - $ob, - $pipeline - ); - } - break; - - case 'UNAVAILABLE': - // Defined by RFC 5530 [3] - $pipeline->data['loginerr'] = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Remote server is temporarily unavailable."), - Horde_Imap_Client_Exception::LOGIN_UNAVAILABLE - ); - break; - - case 'AUTHENTICATIONFAILED': - // Defined by RFC 5530 [3] - $pipeline->data['loginerr'] = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Authentication failed."), - Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED - ); - break; - - case 'AUTHORIZATIONFAILED': - // Defined by RFC 5530 [3] - $pipeline->data['loginerr'] = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Authentication was successful, but authorization failed."), - Horde_Imap_Client_Exception::LOGIN_AUTHORIZATIONFAILED - ); - break; - - case 'EXPIRED': - // Defined by RFC 5530 [3] - $pipeline->data['loginerr'] = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Authentication credentials have expired."), - Horde_Imap_Client_Exception::LOGIN_EXPIRED - ); - break; - - case 'PRIVACYREQUIRED': - // Defined by RFC 5530 [3] - $pipeline->data['loginerr'] = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Operation failed due to a lack of a secure connection."), - Horde_Imap_Client_Exception::LOGIN_PRIVACYREQUIRED - ); - break; - - case 'NOPERM': - // Defined by RFC 5530 [3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("You do not have adequate permissions to carry out this operation."), - Horde_Imap_Client_Exception::NOPERM, - $ob, - $pipeline - ); - - case 'INUSE': - // Defined by RFC 5530 [3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("There was a temporary issue when attempting this operation. Please try again later."), - Horde_Imap_Client_Exception::INUSE, - $ob, - $pipeline - ); - - case 'EXPUNGEISSUED': - // Defined by RFC 5530 [3] - $pipeline->data['expungeissued'] = true; - break; - - case 'CORRUPTION': - // Defined by RFC 5530 [3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The mail server is reporting corrupt data in your mailbox."), - Horde_Imap_Client_Exception::CORRUPTION, - $ob, - $pipeline - ); - - case 'SERVERBUG': - case 'CLIENTBUG': - case 'CANNOT': - // Defined by RFC 5530 [3] - $this->_debug->info( - 'ERROR: mail server explicitly reporting an error.' - ); - break; - - case 'LIMIT': - // Defined by RFC 5530 [3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The mail server has denied the request."), - Horde_Imap_Client_Exception::LIMIT, - $ob, - $pipeline - ); - - case 'OVERQUOTA': - // Defined by RFC 5530 [3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The operation failed because the quota has been exceeded on the mail server."), - Horde_Imap_Client_Exception::OVERQUOTA, - $ob, - $pipeline - ); - - case 'ALREADYEXISTS': - // Defined by RFC 5530 [3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The object could not be created because it already exists."), - Horde_Imap_Client_Exception::ALREADYEXISTS, - $ob, - $pipeline - ); - - case 'NONEXISTENT': - // Defined by RFC 5530 [3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The object could not be deleted because it does not exist."), - Horde_Imap_Client_Exception::NONEXISTENT, - $ob, - $pipeline - ); - - case 'USEATTR': - // Defined by RFC 6154 [3] - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::r("The special-use attribute requested for the mailbox is not supported."), - Horde_Imap_Client_Exception::USEATTR, - $ob, - $pipeline - ); - - case 'DOWNGRADED': - // Defined by RFC 6858 [3] - $downgraded = $this->getIdsOb($rc->data[0]); - foreach ($pipeline->fetch as $val) { - if (in_array($val->getUid(), $downgraded)) { - $val->setDowngraded(true); - } - } - break; - - case 'XPROXYREUSE': - // The proxy connection was reused, so no need to do login tasks. - $pipeline->data['proxyreuse'] = true; - break; - - default: - // Unknown response codes SHOULD be ignored - RFC 3501 [7.1] - break; - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Socket/Catenate.php b/lib/horde/framework/Horde/Imap/Client/Socket/Catenate.php deleted file mode 100644 index b4ebfa4406b..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Socket/Catenate.php +++ /dev/null @@ -1,167 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @internal - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Socket_Catenate -{ - /** - * Socket object. - * - * @var Horde_Imap_Client_Socket - */ - protected $_socket; - - /** - * Constructor. - * - * @param Horde_Imap_Client_Socket $socket Socket object. - */ - public function __construct(Horde_Imap_Client_Socket $socket) - { - $this->_socket = $socket; - } - - /** - * Given an IMAP URL, fetches the corresponding part. - * - * @param Horde_Imap_Client_Url_Imap $url An IMAP URL. - * - * @return resource The section contents in a stream. Returns null if - * the part could not be found. - * - * @throws Horde_Imap_Client_Exception - */ - public function fetchFromUrl(Horde_Imap_Client_Url_Imap $url) - { - $ids_ob = $this->_socket->getIdsOb($url->uid); - - // BODY[] - if (is_null($url->section)) { - $query = new Horde_Imap_Client_Fetch_Query(); - $query->fullText(array( - 'peek' => true - )); - - $fetch = $this->_socket->fetch($url->mailbox, $query, array( - 'ids' => $ids_ob - )); - return $fetch[$url->uid]->getFullMsg(true); - } - - $section = trim($url->section); - - // BODY[<#.>HEADER.FIELDS<.NOT>()] - if (($pos = stripos($section, 'HEADER.FIELDS')) !== false) { - $hdr_pos = strpos($section, '('); - $cmd = substr($section, 0, $hdr_pos); - - $query = new Horde_Imap_Client_Fetch_Query(); - $query->headers( - 'section', - explode(' ', substr($section, $hdr_pos + 1, strrpos($section, ')') - $hdr_pos)), - array( - 'id' => ($pos ? substr($section, 0, $pos - 1) : 0), - 'notsearch' => (stripos($cmd, '.NOT') !== false), - 'peek' => true - ) - ); - - $fetch = $this->_socket->fetch($url->mailbox, $query, array( - 'ids' => $ids_ob - )); - return $fetch[$url->uid]->getHeaders('section', Horde_Imap_Client_Data_Fetch::HEADER_STREAM); - } - - // BODY[#] - if (is_numeric(substr($section, -1))) { - $query = new Horde_Imap_Client_Fetch_Query(); - $query->bodyPart($section, array( - 'peek' => true - )); - - $fetch = $this->_socket->fetch($url->mailbox, $query, array( - 'ids' => $ids_ob - )); - return $fetch[$url->uid]->getBodyPart($section, true); - } - - // BODY[<#.>HEADER] - if (($pos = stripos($section, 'HEADER')) !== false) { - $id = $pos - ? substr($section, 0, $pos - 1) - : 0; - - $query = new Horde_Imap_Client_Fetch_Query(); - $query->headerText(array( - 'id' => $id, - 'peek' => true - )); - - $fetch = $this->_socket->fetch($url->mailbox, $query, array( - 'ids' => $ids_ob - )); - return $fetch[$url->uid]->getHeaderText($id, Horde_Imap_Client_Data_Fetch::HEADER_STREAM); - } - - // BODY[<#.>TEXT] - if (($pos = stripos($section, 'TEXT')) !== false) { - $id = $pos - ? substr($section, 0, $pos - 1) - : 0; - - $query = new Horde_Imap_Client_Fetch_Query(); - $query->bodyText(array( - 'id' => $id, - 'peek' => true - )); - - $fetch = $this->_socket->fetch($url->mailbox, $query, array( - 'ids' => $ids_ob - )); - return $fetch[$url->uid]->getBodyText($id, true); - } - - // BODY[<#.>MIMEHEADER] - if (($pos = stripos($section, 'MIME')) !== false) { - $id = $pos - ? substr($section, 0, $pos - 1) - : 0; - - $query = new Horde_Imap_Client_Fetch_Query(); - $query->mimeHeader($id, array( - 'peek' => true - )); - - $fetch = $this->_socket->fetch($url->mailbox, $query, array( - 'ids' => $ids_ob - )); - return $fetch[$url->uid]->getMimeHeader($id, Horde_Imap_Client_Data_Fetch::HEADER_STREAM); - } - - return null; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Socket/ClientSort.php b/lib/horde/framework/Horde/Imap/Client/Socket/ClientSort.php deleted file mode 100644 index a93853abbeb..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Socket/ClientSort.php +++ /dev/null @@ -1,373 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @internal - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Socket_ClientSort -{ - /** - * Collator object to use for sotring. - * - * @var Collator - */ - protected $_collator; - - /** - * Socket object. - * - * @var Horde_Imap_Client_Socket - */ - protected $_socket; - - /** - * Constructor. - * - * @param Horde_Imap_Client_Socket $socket Socket object. - */ - public function __construct(Horde_Imap_Client_Socket $socket) - { - $this->_socket = $socket; - - if (class_exists('Collator')) { - $this->_collator = new Collator(null); - } - } - - /** - * Sort search results client side if the server does not support the SORT - * IMAP extension (RFC 5256). - * - * @param Horde_Imap_Client_Ids $res The search results. - * @param array $opts The options to _search(). - * - * @return array The sort results. - * - * @throws Horde_Imap_Client_Exception - */ - public function clientSort($res, $opts) - { - if (!count($res)) { - return $res; - } - - /* Generate the FETCH command needed. */ - $query = new Horde_Imap_Client_Fetch_Query(); - - foreach ($opts['sort'] as $val) { - switch ($val) { - case Horde_Imap_Client::SORT_ARRIVAL: - $query->imapDate(); - break; - - case Horde_Imap_Client::SORT_DATE: - $query->imapDate(); - $query->envelope(); - break; - - case Horde_Imap_Client::SORT_CC: - case Horde_Imap_Client::SORT_DISPLAYFROM: - case Horde_Imap_Client::SORT_DISPLAYTO: - case Horde_Imap_Client::SORT_FROM: - case Horde_Imap_Client::SORT_SUBJECT: - case Horde_Imap_Client::SORT_TO: - $query->envelope(); - break; - - case Horde_Imap_Client::SORT_SEQUENCE: - $query->seq(); - break; - - case Horde_Imap_Client::SORT_SIZE: - $query->size(); - break; - } - } - - if (!count($query)) { - return $res; - } - - $mbox = $this->_socket->currentMailbox(); - $fetch_res = $this->_socket->fetch(isset($mbox['mailbox']) ? $mbox['mailbox'] : null, $query, array( - 'ids' => $res - )); - - return $this->_clientSortProcess($res->ids, $fetch_res, $opts['sort']); - } - - /** - * If server does not support the THREAD IMAP extension (RFC 5256), do - * ORDEREDSUBJECT threading on the client side. - * - * @param Horde_Imap_Client_Fetch_Results $data Fetch results. - * @param boolean $uids Are IDs UIDs? - * - * @return array The thread sort results. - */ - public function threadOrderedSubject(Horde_Imap_Client_Fetch_Results $data, - $uids) - { - $dates = $this->_getSentDates($data, $data->ids()); - $out = $sorted = $tsort = array(); - - foreach ($data as $k => $v) { - $subject = strval(new Horde_Imap_Client_Data_BaseSubject($v->getEnvelope()->subject)); - $sorted[$subject][$k] = $dates[$k]; - } - - /* Step 1: Sort by base subject (already done). - * Step 2: Sort by sent date within each thread. */ - foreach (array_keys($sorted) as $key) { - $this->_stableAsort($sorted[$key]); - $tsort[$key] = reset($sorted[$key]); - } - - /* Step 3: Sort by the sent date of the first message in the - * thread. */ - $this->_stableAsort($tsort); - - /* Now, $tsort contains the order of the threads, and each thread - * is sorted in $sorted. */ - foreach (array_keys($tsort) as $key) { - $keys = array_keys($sorted[$key]); - $out[$keys[0]] = array( - $keys[0] => 0 - ) + array_fill_keys(array_slice($keys, 1) , 1); - } - - return new Horde_Imap_Client_Data_Thread( - $out, - $uids ? 'uid' : 'sequence' - ); - } - - /** - */ - protected function _clientSortProcess($res, $fetch_res, $sort) - { - /* The initial sort is on the entire set. */ - $slices = array(0 => $res); - $reverse = false; - - foreach ($sort as $val) { - if ($val == Horde_Imap_Client::SORT_REVERSE) { - $reverse = true; - continue; - } - - $slices_list = $slices; - $slices = array(); - - foreach ($slices_list as $slice_start => $slice) { - $sorted = array(); - - switch ($val) { - case Horde_Imap_Client::SORT_SEQUENCE: - /* There is no requirement that IDs be returned in - * sequence order (see RFC 4549 [4.3.1]). So we must sort - * ourselves. */ - $sorted = array_flip($slice); - ksort($sorted, SORT_NUMERIC); - break; - - case Horde_Imap_Client::SORT_SIZE: - foreach ($slice as $num) { - $sorted[$num] = $fetch_res[$num]->getSize(); - } - asort($sorted, SORT_NUMERIC); - break; - - case Horde_Imap_Client::SORT_DISPLAYFROM: - case Horde_Imap_Client::SORT_DISPLAYTO: - $field = ($val == Horde_Imap_Client::SORT_DISPLAYFROM) - ? 'from' - : 'to'; - - foreach ($slice as $num) { - $ob = $fetch_res[$num]->getEnvelope()->$field; - $sorted[$num] = ($addr_ob = $ob[0]) - ? $addr_ob->personal ?: $addr_ob->mailbox - : null; - } - - $this->_sortString($sorted); - break; - - case Horde_Imap_Client::SORT_CC: - case Horde_Imap_Client::SORT_FROM: - case Horde_Imap_Client::SORT_TO: - if ($val == Horde_Imap_Client::SORT_CC) { - $field = 'cc'; - } elseif ($val == Horde_Imap_Client::SORT_FROM) { - $field = 'from'; - } else { - $field = 'to'; - } - - foreach ($slice as $num) { - $tmp = $fetch_res[$num]->getEnvelope()->$field; - $sorted[$num] = count($tmp) - ? $tmp[0]->mailbox - : null; - } - - $this->_sortString($sorted); - break; - - case Horde_Imap_Client::SORT_ARRIVAL: - $sorted = $this->_getSentDates($fetch_res, $slice, true); - asort($sorted, SORT_NUMERIC); - break; - - case Horde_Imap_Client::SORT_DATE: - // Date sorting rules in RFC 5256 [2.2] - $sorted = $this->_getSentDates($fetch_res, $slice); - asort($sorted, SORT_NUMERIC); - break; - - case Horde_Imap_Client::SORT_SUBJECT: - // Subject sorting rules in RFC 5256 [2.1] - foreach ($slice as $num) { - $sorted[$num] = strval(new Horde_Imap_Client_Data_BaseSubject($fetch_res[$num]->getEnvelope()->subject)); - } - - $this->_sortString($sorted); - break; - } - - // At this point, keys of $sorted are sequence/UID and values - // are the sort strings - if (!empty($sorted)) { - if ($reverse) { - $sorted = array_reverse($sorted, true); - } - - if (count($sorted) === count($res)) { - $res = array_keys($sorted); - } else { - array_splice($res, $slice_start, count($slice), array_keys($sorted)); - } - - // Check for ties. - $last = $start = null; - $i = 0; - $todo = array(); - - foreach ($sorted as $k => $v) { - if (is_null($last) || ($last != $v)) { - if ($i) { - $todo[] = array($start, $i); - $i = 0; - } - $last = $v; - $start = $k; - } else { - ++$i; - } - } - if ($i) { - $todo[] = array($start, $i); - } - - foreach ($todo as $v) { - $slices[array_search($v[0], $res)] = array_keys( - array_slice( - $sorted, - array_search($v[0], $sorted), - $v[1] + 1, - true - ) - ); - } - } - } - - $reverse = false; - } - - return $res; - } - - /** - * Get the sent dates for purposes of SORT/THREAD sorting under RFC 5256 - * [2.2]. - * - * @param Horde_Imap_Client_Fetch_Results $data Data returned from - * fetch() that includes - * both date and envelope - * items. - * @param array $ids The IDs to process. - * @param boolean $internal Only use internal date? - * - * @return array A mapping of IDs -> UNIX timestamps. - */ - protected function _getSentDates(Horde_Imap_Client_Fetch_Results $data, - $ids, $internal = false) - { - $dates = array(); - - foreach ($ids as $num) { - $dt = ($internal || !isset($data[$num]->getEnvelope()->date)) - // RFC 5256 [3] & 3501 [6.4.4]: disregard timezone when - // using internaldate. - ? $data[$num]->getImapDate() - : $data[$num]->getEnvelope()->date; - $dates[$num] = $dt->format('U'); - } - - return $dates; - } - - /** - * Stable asort() function. - * - * PHP's asort() (BWT) is not a stable sort - identical values have no - * guarantee of key order. Use Schwartzian Transform instead. See: - * http://notmysock.org/blog/php/schwartzian-transform.html - * - * @param array &$a Array to sort. - */ - protected function _stableAsort(&$a) - { - array_walk($a, function(&$v, $k) { $v = array($v, $k); }); - asort($a); - array_walk($a, function(&$v, $k) { $v = $v[0]; }); - } - - /** - * Sort an array of strings based on current locale. - * - * @param array &$sorted Array of strings. - */ - protected function _sortString(&$sorted) - { - if (empty($this->_collator)) { - asort($sorted, SORT_LOCALE_STRING); - } else { - $this->_collator->asort($sorted, Collator::SORT_STRING); - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Socket/Connection/Base.php b/lib/horde/framework/Horde/Imap/Client/Socket/Connection/Base.php deleted file mode 100644 index 2a03cb07c23..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Socket/Connection/Base.php +++ /dev/null @@ -1,76 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @internal - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Socket_Connection_Base extends Horde\Socket\Client -{ - /** - * Protocol type. - * - * @var string - */ - protected $_protocol = 'imap'; - - /** - */ - protected function _connect($host, $port, $timeout, $secure, $context, $retries = 0) - { - if ($retries || !$this->_params['debug']->debug) { - $timer = null; - } else { - $url = ($this->_protocol == 'imap') - ? new Horde_Imap_Client_Url_Imap() - : new Horde_Imap_Client_Url_Pop3(); - $url->host = $host; - $url->port = $port; - $this->_params['debug']->info(sprintf( - 'Connection to: %s', - strval($url) - )); - - $timer = new Horde_Support_Timer(); - $timer->push(); - } - - try { - parent::_connect($host, $port, $timeout, $secure, $context, $retries); - } catch (Horde\Socket\Client\Exception $e) { - $this->_params['debug']->info(sprintf( - 'Connection failed: %s', - $e->getMessage() - )); - throw $e; - } - - if ($timer) { - $this->_params['debug']->info(sprintf( - 'Server connection took %s seconds.', - round($timer->pop(), 4) - )); - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Socket/Connection/Pop3.php b/lib/horde/framework/Horde/Imap/Client/Socket/Connection/Pop3.php deleted file mode 100644 index 260b070e977..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Socket/Connection/Pop3.php +++ /dev/null @@ -1,93 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @internal - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Socket_Connection_Pop3 -extends Horde_Imap_Client_Socket_Connection_Base -{ - /** - */ - protected $_protocol = 'pop3'; - - /** - * Writes data to the POP3 output stream. - * - * @param string $data String data. - * @param boolean $debug Output line to debug? - * - * @throws Horde_Imap_Client_Exception - */ - public function write($data, $debug = true) - { - if (fwrite($this->_stream, $data . "\r\n") === false) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Server write error."), - Horde_Imap_Client_Exception::SERVER_WRITEERROR - ); - } - - if ($debug) { - $this->_params['debug']->client($data); - } - } - - /** - * Read data from incoming POP3 stream. - * - * @param integer $size UNUSED: The number of bytes to read from the - * socket. - * - * @return string Line of data. - * - * @throws Horde_Imap_Client_Exception - */ - public function read($size = null) - { - if (feof($this->_stream)) { - $this->close(); - $this->_params['debug']->info( - 'ERROR: Server closed the connection.' - ); - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Server closed the connection unexpectedly."), - Horde_Imap_Client_Exception::DISCONNECT - ); - } - - if (($read = fgets($this->_stream)) === false) { - $this->_params['debug']->info('ERROR: read/timeout error.'); - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error when communicating with the mail server."), - Horde_Imap_Client_Exception::SERVER_READERROR - ); - } - - $this->_params['debug']->server(rtrim($read, "\r\n")); - - return $read; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Socket/Connection/Socket.php b/lib/horde/framework/Horde/Imap/Client/Socket/Connection/Socket.php deleted file mode 100644 index ff2274981e9..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Socket/Connection/Socket.php +++ /dev/null @@ -1,222 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @internal - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Socket_Connection_Socket -extends Horde_Imap_Client_Socket_Connection_Base -{ - /** - * If false, does not outpt the current line of client output to debug. - * - * @var boolean - */ - public $client_debug = true; - - /** - * Sending buffer. - * - * @var string - */ - protected $_buffer = ''; - - /** - * Writes data to the IMAP output stream. - * - * @param string $data String data. - * @param boolean $eol Append EOL? - * - * @throws Horde_Imap_Client_Exception - */ - public function write($data, $eol = false) - { - if ($eol) { - $buffer = $this->_buffer; - $debug = $this->client_debug; - $this->_buffer = ''; - - $this->client_debug = true; - - if (fwrite($this->_stream, $buffer . $data . ($eol ? "\r\n" : '')) === false) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Server write error."), - Horde_Imap_Client_Exception::SERVER_WRITEERROR - ); - } - - if ($debug) { - $this->_params['debug']->client($buffer . $data); - } - } else { - $this->_buffer .= $data; - } - } - - /** - * Writes literal data to the IMAP output stream. - * - * @param mixed $data Either a stream resource, or Horde_Stream - * object. - * @param integer $length The literal length. - * @param boolean $binary If true, this is binary data. - * - * @throws Horde_Imap_Client_Exception - */ - public function writeLiteral($data, $length, $binary = false) - { - $this->_buffer = ''; - $success = false; - - if ($data instanceof Horde_Stream) { - $data = $data->stream; - } - - if (rewind($data)) { - $success = true; - while (!feof($data)) { - if ((($read_data = fread($data, 8192)) === false) || - (fwrite($this->_stream, $read_data) === false)) { - $success = false; - break; - } - } - } - - if (!$success) { - $this->client_debug = true; - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Server write error."), - Horde_Imap_Client_Exception::SERVER_WRITEERROR - ); - } - - if ($this->client_debug && !empty($this->_params['debugliteral'])) { - rewind($data); - while (!feof($data)) { - $this->_params['debug']->raw(fread($data, 8192)); - } - } else { - $this->_params['debug']->client('[' . ($binary ? 'BINARY' : 'LITERAL') . ' DATA: ' . $length . ' bytes]'); - } - } - - /** - * Read data from incoming IMAP stream. - * - * @param integer $size UNUSED: The number of bytes to read from the - * socket. - * - * @return Horde_Imap_Client_Tokenize The tokenized data. - * - * @throws Horde_Imap_Client_Exception - */ - public function read($size = null) - { - $got_data = false; - $literal_len = null; - $token = new Horde_Imap_Client_Tokenize(); - - do { - if (feof($this->_stream)) { - $this->close(); - $this->_params['debug']->info( - 'ERROR: Server closed the connection.' - ); - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Mail server closed the connection unexpectedly."), - Horde_Imap_Client_Exception::DISCONNECT - ); - } - - if (is_null($literal_len)) { - $buffer = ''; - - while (($in = fgets($this->_stream)) !== false) { - $got_data = true; - - if (substr($in, -1) === "\n") { - $in = rtrim($in); - $this->_params['debug']->server($buffer . $in); - $token->add($in); - break; - } - - $buffer .= $in; - $token->add($in); - } - - /* Check for literal data. */ - if (is_null($len = $token->getLiteralLength())) { - break; - } - - // Skip 0-length literal data. - if ($len['length']) { - $binary = $len['binary']; - $literal_len = $len['length']; - } - - continue; - } - - $old_len = $literal_len; - - while (($literal_len > 0) && !feof($this->_stream)) { - $in = fread($this->_stream, min($literal_len, 8192)); - /* Only store in stream if this is something more than a - * nominal number of bytes. */ - if ($old_len > 256) { - $token->addLiteralStream($in); - } else { - $token->add($in); - } - - if (!empty($this->_params['debugliteral'])) { - $this->_params['debug']->raw($in); - } - - $got_data = true; - $literal_len -= strlen($in); - } - - $literal_len = null; - - if (empty($this->_params['debugliteral'])) { - $this->_params['debug']->server('[' . ($binary ? 'BINARY' : 'LITERAL') . ' DATA: ' . $old_len . ' bytes]'); - } - } while (true); - - if (!$got_data) { - $this->_params['debug']->info('ERROR: read/timeout error.'); - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error when communicating with the mail server."), - Horde_Imap_Client_Exception::SERVER_READERROR - ); - } - - return $token; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Socket/Pop3.php b/lib/horde/framework/Horde/Imap/Client/Socket/Pop3.php deleted file mode 100644 index 68382428d2c..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Socket/Pop3.php +++ /dev/null @@ -1,1543 +0,0 @@ - - * Damian Fernandez Sosa - * - * Copyright (c) 2002, Richard Heyes - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * o Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * o Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * o The names of the authors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * --------------------------------------------------------------------------- - * - * @category Horde - * @copyright 2002 Richard Heyes - * @copyright 2009-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ - -/** - * An interface to a POP3 server using PHP functions. - * - * It is an abstraction layer allowing POP3 commands to be used based on - * IMAP equivalents. - * - * This driver implements the following POP3-related RFCs: - *
- *   - STD 53/RFC 1939: POP3 specification
- *   - RFC 2195: CRAM-MD5 authentication
- *   - RFC 2449: POP3 extension mechanism
- *   - RFC 2595/4616: PLAIN authentication
- *   - RFC 2831: DIGEST-MD5 SASL Authentication (obsoleted by RFC 6331)
- *   - RFC 3206: AUTH/SYS response codes
- *   - RFC 4616: AUTH=PLAIN
- *   - RFC 5034: POP3 SASL
- *   - RFC 5802: AUTH=SCRAM-SHA-1
- *   - RFC 6856: UTF8, LANG
- * 
- * - * @author Richard Heyes - * @author Michael Slusarz - * @category Horde - * @copyright 2002 Richard Heyes - * @copyright 2009-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Socket_Pop3 extends Horde_Imap_Client_Base -{ - /* Internal key used to store mailbox level cache data. \1 is not a valid - * ID in POP3, so it should be safe to use. */ - const MBOX_CACHE = "\1mbox"; - - /** - * The default ports to use for a connection. - * - * @var array - */ - protected $_defaultPorts = array(110, 995); - - /** - * The list of deleted messages. - * - * @var array - */ - protected $_deleted = array(); - - /** - * This object returns POP3 Fetch data objects. - * - * @var string - */ - protected $_fetchDataClass = 'Horde_Imap_Client_Data_Fetch_Pop3'; - - /** - */ - public function __get($name) - { - $out = parent::__get($name); - - switch ($name) { - case 'url': - $out->protocol = 'pop3'; - break; - } - - return $out; - } - - /** - */ - protected function _initCache($current = false) - { - return parent::_initCache($current) && - $this->_capability('UIDL'); - } - - /** - */ - public function getIdsOb($ids = null, $sequence = false) - { - return new Horde_Imap_Client_Ids_Pop3($ids, $sequence); - } - - /** - */ - protected function _initCapability() - { - $this->_connect(); - - $c = new Horde_Imap_Client_Data_Capability(); - - try { - $res = $this->_sendLine('CAPA', array( - 'multiline' => 'array' - )); - - foreach ($res['data'] as $val) { - $prefix = explode(' ', $val); - $c->add($prefix[0], array_slice($prefix, 1)); - } - } catch (Horde_Imap_Client_Exception $e) { - $this->_temp['no_capa'] = true; - - /* Need to probe for capabilities if CAPA command is not - * available. */ - $c->add('USER'); - - /* Capability sniffing only guaranteed after authentication is - * completed (if any). */ - if (!empty($this->_init['authmethod'])) { - $this->_pop3Cache('uidl'); - if (empty($this->_temp['no_uidl'])) { - $c->add('UIDL'); - } - - $this->_pop3Cache('top', 1); - if (empty($this->_temp['no_top'])) { - $c->add('TOP'); - } - } - } - - $this->_setInit('capability', $c); - } - - /** - */ - protected function _noop() - { - $this->_sendLine('NOOP'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _getNamespaces() - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Namespaces'); - } - - /** - */ - protected function _login() - { - /* Blank passwords are not allowed, so no need to even try - * authentication to determine this. */ - if (!strlen($this->getParam('password'))) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("No password provided."), - Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED - ); - } - - $this->_connect(); - - $first_login = empty($this->_init['authmethod']); - - // Switch to secure channel if using TLS. - if (!$this->isSecureConnection()) { - $secure = $this->getParam('secure'); - - if (($secure === 'tls') || $secure === true) { - // Switch over to a TLS connection. - if ($first_login && !$this->_capability('STLS')) { - if ($secure === 'tls') { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Could not open secure connection to the POP3 server.") . ' ' . Horde_Imap_Client_Translation::r("Server does not support secure connections."), - Horde_Imap_Client_Exception::LOGIN_TLSFAILURE - ); - } else { - $this->setParam('secure', false); - } - } else { - $this->_sendLine('STLS'); - - $this->setParam('secure', 'tls'); - - if (!$this->_connection->startTls()) { - $this->logout(); - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Could not open secure connection to the POP3 server."), - Horde_Imap_Client_Exception::LOGIN_TLSFAILURE - ); - } - $this->_debug->info('Successfully completed TLS negotiation.'); - } - - // Expire cached CAPABILITY information - $this->_setInit('capability'); - } else { - $this->setParam('secure', false); - } - } - - if ($first_login) { - /* At least one server (Dovecot 1.x) may return SASL capability - * with no arguments. */ - $auth_mech = $this->_capability()->getParams('SASL'); - - if (isset($this->_temp['pop3timestamp'])) { - $auth_mech[] = 'APOP'; - } - - $auth_mech[] = 'USER'; - - /* Enable UTF-8 mode (RFC 6856). MUST occur after STLS is - * issued. */ - if ($this->_capability('UTF8')) { - try { - $this->_sendLine('UTF8'); - $this->_temp['utf8'] = true; - } catch (Horde_Imap_Client_Exception $e) { - /* If server responds to UTF8 command with error, - * fallback to legacy non-UTF8 behavior. */ - } - } - } else { - $auth_mech = array($this->_init['authmethod']); - } - - foreach ($auth_mech as $method) { - try { - $this->_tryLogin($method); - $this->_setInit('authmethod', $method); - - if (!empty($this->_temp['no_capa']) || - !$this->_capability('UIDL')) { - $this->_setInit('capability'); - } - - return true; - } catch (Horde_Imap_Client_Exception $e) { - if (!empty($this->_init['authmethod']) && - ($e->getCode() != $e::LOGIN_UNAVAILABLE) && - ($e->getCode() != $e::POP3_TEMP_ERROR)) { - $this->_setInit(); - return $this->login(); - } - } - } - - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("POP3 server denied authentication."), - $e->getCode() ?: $e::LOGIN_AUTHENTICATIONFAILED - ); - } - - /** - * Connects to the server. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _connect() - { - if (!is_null($this->_connection)) { - return; - } - - try { - $this->_connection = new Horde_Imap_Client_Socket_Connection_Pop3( - $this->getParam('hostspec'), - $this->getParam('port'), - $this->getParam('timeout'), - $this->getParam('secure'), - $this->getParam('context'), - array( - 'debug' => $this->_debug - ) - ); - } catch (Horde\Socket\Client\Exception $e) { - $e2 = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error connecting to mail server."), - Horde_Imap_Client_Exception::SERVER_CONNECT - ); - $e2->details = $e->details; - throw $e2; - } - - $line = $this->_getResponse(); - - // Check for string matching APOP timestamp - if (preg_match('/<.+@.+>/U', $line['resp'], $matches)) { - $this->_temp['pop3timestamp'] = $matches[0]; - } - } - - /** - * Authenticate to the POP3 server. - * - * @param string $method POP3 login method. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _tryLogin($method) - { - $username = $this->getParam('username'); - $password = $this->getParam('password'); - - switch ($method) { - case 'CRAM-MD5': - case 'CRAM-SHA1': - case 'CRAM-SHA256': - // RFC 5034: CRAM-MD5 - // CRAM-SHA1 & CRAM-SHA256 supported by Courier SASL library - $challenge = $this->_sendLine('AUTH ' . $method); - $response = base64_encode($username . ' ' . hash_hmac(Horde_String::lower(substr($method, 5)), base64_decode(substr($challenge['resp'], 2)), $password, true)); - $this->_sendLine($response, array( - 'debug' => sprintf('[AUTH Response (username: %s)]', $username) - )); - break; - - case 'DIGEST-MD5': - // RFC 2831; Obsoleted by RFC 6331 - $challenge = $this->_sendLine('AUTH DIGEST-MD5'); - $response = base64_encode(new Horde_Imap_Client_Auth_DigestMD5( - $username, - $password, - base64_decode(substr($challenge['resp'], 2)), - $this->getParam('hostspec'), - 'pop3' - )); - $sresponse = $this->_sendLine($response, array( - 'debug' => sprintf('[AUTH Response (username: %s)]', $username) - )); - if (stripos(base64_decode(substr($sresponse['resp'], 2)), 'rspauth=') === false) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Unexpected response from server when authenticating."), - Horde_Imap_Client_Exception::SERVER_CONNECT - ); - } - - /* POP3 doesn't use protocol's third step. */ - $this->_sendLine(''); - break; - - case 'LOGIN': - // RFC 4616 (AUTH=PLAIN) & 5034 (POP3 SASL) - $this->_sendLine('AUTH LOGIN'); - $this->_sendLine(base64_encode($username)); - $this->_sendLine(base64_encode($password), array( - 'debug' => sprintf('[AUTH Password (username: %s)]', $username) - )); - break; - - case 'PLAIN': - // RFC 5034 - $this->_sendLine('AUTH PLAIN ' . base64_encode(implode("\0", array( - $username, - $username, - $password - ))), array( - 'debug' => sprintf('AUTH PLAIN [Auth Response (username: %s)]', $username) - )); - break; - - case 'APOP': - /* If UTF8 (+ USER) is active, and non-ASCII exists, need to apply - * SASLprep to username/password. RFC 6856[2.2]. Reject if - * UTF8 (+ USER) is not supported and 8-bit characters exist. */ - if (Horde_Mime::is8bit($username) || - Horde_Mime::is8bit($password)) { - if (empty($this->_temp['utf8']) || - !$this->_capability('UTF8', 'USER') || - !class_exists('Horde_Stringprep')) { - $error = true; - } else { - Horde_Stringprep::autoload(); - $saslprep = new Znerol\Component\Stringprep\Profile\SASLprep(); - - try { - $username = $saslprep->apply( - $username, - 'UTF-8', - Znerol\Compnonent\Stringprep\Profile::MODE_QUERY - ); - $password = $saslprep->apply( - $password, - 'UTF-8', - Znerol\Compnonent\Stringprep\Profile::MODE_STORE - ); - $error = false; - } catch (Znerol\Component\Stringprep\ProfileException $e) { - $error = true; - } - } - - if ($error) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Authentication failed."), - Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED - ); - } - } - - // RFC 1939 [7] - $this->_sendLine('APOP ' . $username . ' ' . - hash('md5', $this->_temp['pop3timestamp'] . $password)); - break; - - case 'USER': - /* POP3 servers without UTF8 (+ USER) does not accept non-ASCII - * in USER/PASS. RFC 6856[2.2] */ - if ((empty($this->_temp['utf8']) || - !$this->_capability('UTF8', 'USER')) && - (Horde_Mime::is8bit($username) || - Horde_Mime::is8bit($password))) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Authentication failed."), - Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED - ); - } - - // RFC 1939 [7] - $this->_sendLine('USER ' . $username); - $this->_sendLine('PASS ' . $password, array( - 'debug' => 'PASS [Password]' - )); - break; - - case 'SCRAM-SHA-1': - $scram = new Horde_Imap_Client_Auth_Scram( - $username, - $password, - 'SHA1' - ); - - $c1 = $this->_sendLine( - 'AUTH ' . $method . ' ' . base64_encode($scram->getClientFirstMessage()) - ); - - $sr1 = base64_decode(substr($c1['resp'], 2)); - if (!$scram->parseServerFirstMessage($sr1)) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Authentication failed."), - Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED - ); - } - - $c2 = $this->_sendLine( - base64_encode($scram->getClientFinalMessage()) - ); - - $sr2 = base64_decode(substr($c2['resp'], 2)); - if (!$scram->parseServerFirstMessage($sr)) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Authentication failed."), - Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED - ); - - /* This means authentication passed, according to the server, - * but the server signature is incorrect. This indicates that - * server verification has failed. Immediately disconnect from - * the server, since this is a possible security issue. */ - $this->logout(); - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Server failed verification check."), - Horde_Imap_Client_Exception::LOGIN_SERVER_VERIFICATION_FAILED - ); - } - - $this->_sendLine(''); - break; - - default: - $e = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Unknown authentication method: %s"), - Horde_Imap_Client_Exception::SERVER_CONNECT - ); - $e->messagePrintf(array($method)); - throw $e; - } - } - - /** - */ - protected function _logout() - { - try { - $this->_sendLine('QUIT'); - } catch (Horde_Imap_Client_Exception $e) {} - $this->_deleted = array(); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _sendID($info) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('ID command'); - } - - /** - * Return implementation information from the POP3 server (RFC 2449 [6.9]). - */ - protected function _getID() - { - return ($id = $this->_capability()->getParams('IMPLEMENTATION')) - ? array('implementation' => reset($id)) - : array(); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _setLanguage($langs) - { - // RFC 6856 [3] - if (!$this->_capability('LANG')) { - throw new Horde_Imap_Client_Exception_NoSupportPop3('LANGUAGE extension'); - } - - foreach ($langs as $val) { - try { - $this->_sendLine('LANG ' . $val); - $this->_temp['lang'] = $val; - } catch (Horde_Imap_Client_Exception $e) { - // Setting language failed - move on to next one. - } - } - - return $this->_getLanguage(false); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _getLanguage($list) - { - // RFC 6856 [3] - if (!$this->_capability('LANG')) { - throw new Horde_Imap_Client_Exception_NoSupportPop3('LANGUAGE extension'); - } - - if (!$list) { - return isset($this->_temp['lang']) - ? $this->_temp['lang'] - : null; - } - - $langs = array(); - - try { - $res = $this->_sendLine('LANG', array( - 'multiline' => 'array' - )); - - foreach ($res['data'] as $val) { - $parts = explode(' ', $val); - $langs[] = $parts[0]; - // $parts[1] - lanuage description (not used) - } - } catch (Horde_Imap_Client_Exception $e) { - // Ignore: language listing might fail. RFC 6856 [3.3] - } - - return $langs; - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _openMailbox(Horde_Imap_Client_Mailbox $mailbox, $mode) - { - if ($mailbox != 'INBOX') { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Mailboxes other than INBOX'); - } - $this->_changeSelected($mailbox, $mode); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _createMailbox(Horde_Imap_Client_Mailbox $mailbox, $opts) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Creating mailboxes'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _deleteMailbox(Horde_Imap_Client_Mailbox $mailbox) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Deleting mailboxes'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _renameMailbox(Horde_Imap_Client_Mailbox $old, - Horde_Imap_Client_Mailbox $new) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Renaming mailboxes'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _subscribeMailbox(Horde_Imap_Client_Mailbox $mailbox, - $subscribe) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Mailboxes other than INBOX'); - } - - /** - */ - protected function _listMailboxes($pattern, $mode, $options) - { - if (empty($options['flat'])) { - return array( - 'INBOX' => array( - 'attributes' => array(), - 'delimiter' => '', - 'mailbox' => Horde_Imap_Client_Mailbox::get('INBOX') - ) - ); - } - - return array('INBOX' => Horde_Imap_Client_Mailbox::get('INBOX')); - } - - /** - * @param integer $flags This driver only supports the options listed - * under Horde_Imap_Client::STATUS_ALL. - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _status($mboxes, $flags) - { - if ((count($mboxes) > 1) || (reset($mboxes) != 'INBOX')) { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Mailboxes other than INBOX'); - } - - $this->openMailbox('INBOX'); - - $ret = array(); - - if ($flags & Horde_Imap_Client::STATUS_MESSAGES) { - $res = $this->_pop3Cache('stat'); - $ret['messages'] = $res['msgs']; - } - - if ($flags & Horde_Imap_Client::STATUS_RECENT) { - $res = $this->_pop3Cache('stat'); - $ret['recent'] = $res['msgs']; - } - - // No need for STATUS_UIDNEXT_FORCE handling since STATUS_UIDNEXT will - // always return a value. - $uidl = $this->_capability('UIDL'); - if ($flags & Horde_Imap_Client::STATUS_UIDNEXT) { - if ($uidl) { - $ctx = hash_init('md5'); - foreach ($this->_pop3Cache('uidl') as $key => $val) { - hash_update($ctx, '|' . $key . '|' . $val); - } - $ret['uidnext'] = hash_final($ctx); - } else { - $res = $this->_pop3Cache('stat'); - $ret['uidnext'] = $res['msgs'] + 1; - } - } - - if ($flags & Horde_Imap_Client::STATUS_UIDVALIDITY) { - $ret['uidvalidity'] = $uidl - ? 1 - : microtime(true); - } - - if ($flags & Horde_Imap_Client::STATUS_UNSEEN) { - $ret['unseen'] = 0; - } - - return array('INBOX' => $ret); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _append(Horde_Imap_Client_Mailbox $mailbox, $data, - $options) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Appending messages'); - } - - /** - */ - protected function _check() - { - $this->noop(); - } - - /** - */ - protected function _close($options) - { - if (!empty($options['expunge'])) { - $this->logout(); - } - } - - /** - * @param array $options Additional options. 'ids' has no effect in this - * driver. - */ - protected function _expunge($options) - { - $msg_list = $this->_deleted; - $this->logout(); - return empty($options['list']) - ? null - : $msg_list; - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _search($query, $options) - { - $sort = empty($options['sort']) - ? null - : reset($options['sort']); - - // Only support a single query: an ALL search sorted by sequence. - if ((strval($options['_query']['query']) != 'ALL') || - ($sort && - ((count($options['sort']) > 1) || - ($sort != Horde_Imap_Client::SORT_SEQUENCE)))) { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Server search'); - } - - $status = $this->status($this->_selected, Horde_Imap_Client::STATUS_MESSAGES); - $res = range(1, $status['messages']); - - if (empty($options['sequence'])) { - $tmp = array(); - $uidllist = $this->_pop3Cache('uidl'); - foreach ($res as $val) { - $tmp[] = $uidllist[$val]; - } - $res = $tmp; - } - - if (!empty($options['partial'])) { - $partial = $this->getIdsOb($options['partial'], true); - $min = $partial->min - 1; - $res = array_slice($res, $min, $partial->max - $min); - } - - $ret = array(); - foreach ($options['results'] as $val) { - switch ($val) { - case Horde_Imap_Client::SEARCH_RESULTS_COUNT: - $ret['count'] = count($res); - break; - - case Horde_Imap_Client::SEARCH_RESULTS_MATCH: - $ret['match'] = $this->getIdsOb($res); - break; - - case Horde_Imap_Client::SEARCH_RESULTS_MAX: - $ret['max'] = empty($res) ? null : max($res); - break; - - case Horde_Imap_Client::SEARCH_RESULTS_MIN: - $ret['min'] = empty($res) ? null : min($res); - break; - } - } - - return $ret; - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _setComparator($comparator) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Search comparators'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _getComparator() - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Search comparators'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _thread($options) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Server threading'); - } - - /** - */ - protected function _fetch(Horde_Imap_Client_Fetch_Results $results, - $queries) - { - foreach ($queries as $options) { - $this->_fetchCmd($results, $options); - } - - $this->_updateCache($results); - } - - /** - * Fetch data for a given fetch query. - * - * @param Horde_Imap_Client_Fetch_Results $results Fetch results. - * @param array $options Fetch query options. - */ - protected function _fetchCmd(Horde_Imap_Client_Fetch_Results $results, - $options) - { - // Grab sequence IDs - IDs will always be the message number for - // POP3 fetch commands. - $seq_ids = $this->_getSeqIds($options['ids']); - if (empty($seq_ids)) { - return; - } - - $lookup = $options['ids']->sequence - ? array_combine($seq_ids, $seq_ids) - : $this->_pop3Cache('uidl'); - - foreach ($options['_query'] as $type => $c_val) { - switch ($type) { - case Horde_Imap_Client::FETCH_FULLMSG: - foreach ($seq_ids as $id) { - $tmp = $this->_pop3Cache('msg', $id); - - if (empty($c_val['start']) && empty($c_val['length'])) { - $tmp2 = fopen('php://temp', 'r+'); - stream_copy_to_stream($tmp, $tmp2, empty($c_val['length']) ? -1 : $c_val['length'], empty($c_val['start']) ? 0 : $c_val['start']); - $results->get($lookup[$id])->setFullMsg($tmp2); - } else { - $results->get($lookup[$id])->setFullMsg($tmp); - } - } - break; - - case Horde_Imap_Client::FETCH_HEADERTEXT: - // Ignore 'peek' option - foreach ($c_val as $key => $val) { - foreach ($seq_ids as $id) { - /* Message header can be retrieved via TOP, if the - * command is available. */ - try { - $tmp = ($key == 0) - ? $this->_pop3Cache('hdr', $id) - : Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $id)), 'header', $key); - $results->get($lookup[$id])->setHeaderText($key, $this->_processString($tmp, $c_val)); - } catch (Horde_Mime_Exception $e) {} - } - } - break; - - case Horde_Imap_Client::FETCH_BODYTEXT: - // Ignore 'peek' option - foreach ($c_val as $key => $val) { - foreach ($seq_ids as $id) { - try { - $results->get($lookup[$id])->setBodyText($key, $this->_processString(Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $id)), 'body', $key), $val)); - } catch (Horde_Mime_Exception $e) {} - } - } - break; - - case Horde_Imap_Client::FETCH_MIMEHEADER: - // Ignore 'peek' option - foreach ($c_val as $key => $val) { - foreach ($seq_ids as $id) { - try { - $results->get($lookup[$id])->setMimeHeader($key, $this->_processString(Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $id)), 'header', $key), $val)); - } catch (Horde_Mime_Exception $e) {} - } - } - break; - - case Horde_Imap_Client::FETCH_BODYPART: - // Ignore 'decode', 'peek' - foreach ($c_val as $key => $val) { - foreach ($seq_ids as $id) { - try { - $results->get($lookup[$id])->setBodyPart($key, $this->_processString(Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $id)), 'body', $key), $val)); - } catch (Horde_Mime_Exception $e) {} - } - } - break; - - case Horde_Imap_Client::FETCH_HEADERS: - // Ignore 'length', 'peek' - foreach ($seq_ids as $id) { - $ob = $this->_pop3Cache('hdrob', $id); - foreach ($c_val as $key => $val) { - $tmp = $ob; - - if (empty($val['notsearch'])) { - $tmp2 = $tmp->toArray(array('nowrap' => true)); - foreach (array_keys($tmp2) as $hdr) { - if (!in_array($hdr, $val['headers'])) { - unset($tmp[$hdr]); - } - } - } else { - foreach ($val['headers'] as $hdr) { - unset($tmp[$hdr]); - } - } - - $results->get($lookup[$id])->setHeaders($key, $tmp); - } - } - break; - - case Horde_Imap_Client::FETCH_STRUCTURE: - foreach ($seq_ids as $id) { - if ($ptr = $this->_pop3Cache('msg', $id)) { - try { - $results->get($lookup[$id])->setStructure(Horde_Mime_Part::parseMessage(stream_get_contents($ptr), array('no_body' => true))); - } catch (Horde_Exception $e) {} - } - } - break; - - case Horde_Imap_Client::FETCH_ENVELOPE: - foreach ($seq_ids as $id) { - $tmp = $this->_pop3Cache('hdrob', $id); - $results->get($lookup[$id])->setEnvelope(array( - 'date' => $tmp['Date'], - 'subject' => $tmp['Subject'], - 'from' => ($h = $tmp['From']) ? $h->getAddressList(true) : null, - 'sender' => ($h = $tmp['Sender']) ? $h->getAddressList(true) : null, - 'reply_to' => ($h = $tmp['Reply-to']) ? $h->getAddressList(true) : null, - 'to' => ($h = $tmp['To']) ? $h->getAddressList(true) : null, - 'cc' => ($h = $tmp['Cc']) ? $h->getAddressList(true) : null, - 'bcc' => ($h = $tmp['Bcc']) ? $h->getAddressList(true) : null, - 'in_reply_to' => $tmp['In-Reply-To'], - 'message_id' => $tmp['Message-ID'] - )); - } - break; - - case Horde_Imap_Client::FETCH_IMAPDATE: - foreach ($seq_ids as $id) { - $tmp = $this->_pop3Cache('hdrob', $id); - $results->get($lookup[$id])->setImapDate($tmp['Date']); - } - break; - - case Horde_Imap_Client::FETCH_SIZE: - $sizelist = $this->_pop3Cache('size'); - foreach ($seq_ids as $id) { - $results->get($lookup[$id])->setSize($sizelist[$id]); - } - break; - - case Horde_Imap_Client::FETCH_SEQ: - foreach ($seq_ids as $id) { - $results->get($lookup[$id])->setSeq($id); - } - break; - - case Horde_Imap_Client::FETCH_UID: - $uidllist = $this->_pop3Cache('uidl'); - foreach ($seq_ids as $id) { - if (isset($uidllist[$id])) { - $results->get($lookup[$id])->setUid($uidllist[$id]); - } - } - break; - } - } - } - - /** - * Retrieve locally cached message data. - * - * @param string $type Either 'hdr', 'hdrob', 'msg', 'size', 'stat', - * 'top', or 'uidl'. - * @param integer $index The message index. - * @param mixed $data Additional information needed. - * - * @return mixed The cached data. 'msg' returns a stream resource. All - * other types return strings. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _pop3Cache( - $type, $index = self::MBOX_CACHE, $data = null - ) - { - if (isset($this->_temp['pop3cache'][$index][$type])) { - if ($type == 'msg') { - rewind($this->_temp['pop3cache'][$index][$type]); - } - return $this->_temp['pop3cache'][$index][$type]; - } - - switch ($type) { - case 'hdr': - case 'top': - $data = null; - if (($type == 'top') || $this->_capability('TOP')) { - try { - $res = $this->_sendLine('TOP ' . $index . ' 0', array( - 'multiline' => 'stream' - )); - rewind($res['data']); - $data = stream_get_contents($res['data']); - fclose($res['data']); - } catch (Horde_Imap_Client_Exception $e) { - $this->_temp['no_top'] = true; - if ($type == 'top') { - return null; - } - } - } - - if (is_null($data)) { - $data = Horde_Mime_Part::getRawPartText(stream_get_contents($this->_pop3Cache('msg', $index)), 'header', 0); - } - break; - - case 'hdrob': - $data = Horde_Mime_Headers::parseHeaders($this->_pop3Cache('hdr', $index)); - break; - - case 'msg': - $res = $this->_sendLine('RETR ' . $index, array( - 'multiline' => 'stream' - )); - $data = $res['data']; - rewind($data); - break; - - case 'size': - case 'uidl': - $data = array(); - try { - $res = $this->_sendLine(($type == 'size') ? 'LIST' : 'UIDL', array( - 'multiline' => 'array' - )); - foreach ($res['data'] as $val) { - $resp_data = explode(' ', $val, 2); - $data[$resp_data[0]] = $resp_data[1]; - } - } catch (Horde_Imap_Client_Exception $e) { - if ($type == 'uidl') { - $this->_temp['no_uidl'] = true; - } - } - break; - - case 'stat': - $resp = $this->_sendLine('STAT'); - $resp_data = explode(' ', $resp['resp'], 2); - $data = array('msgs' => $resp_data[0], 'size' => $resp_data[1]); - break; - } - - $this->_temp['pop3cache'][$index][$type] = $data; - - return $data; - } - - /** - * Process a string response based on criteria options. - * - * @param string $str The original string. - * @param array $opts The criteria options. - * - * @return string The requested string. - */ - protected function _processString($str, $opts) - { - if (!empty($opts['length'])) { - return substr($str, empty($opts['start']) ? 0 : $opts['start'], $opts['length']); - } elseif (!empty($opts['start'])) { - return substr($str, $opts['start']); - } - - return $str; - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _vanished($modseq, Horde_Imap_Client_Ids $ids) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('QRESYNC commands'); - } - - /** - * @param array $options Additional options. This driver does not support - * 'unchangedsince'. - */ - protected function _store($options) - { - $delete = $reset = false; - - /* Only support deleting/undeleting messages. */ - if (isset($options['replace'])) { - $delete = (bool)(count(array_intersect($options['replace'], array( - Horde_Imap_Client::FLAG_DELETED - )))); - $reset = !$delete; - } else { - if (!empty($options['add'])) { - $delete = (bool)(count(array_intersect($options['add'], array( - Horde_Imap_Client::FLAG_DELETED - )))); - } - - if (!empty($options['remove'])) { - $reset = !(bool)(count(array_intersect($options['remove'], array( - Horde_Imap_Client::FLAG_DELETED - )))); - } - } - - if ($reset) { - $this->_sendLine('RSET'); - } elseif ($delete) { - foreach ($this->_getSeqIds($options['ids']) as $id) { - try { - $this->_sendLine('DELE ' . $id); - $this->_deleted[] = $id; - - unset( - $this->_temp['pop3cache'][self::MBOX_CACHE], - $this->_temp['pop3cache'][$id] - ); - } catch (Horde_Imap_Client_Exception $e) {} - } - } - - return $this->getIdsOb(); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _copy(Horde_Imap_Client_Mailbox $dest, $options) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Copying messages'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _setQuota(Horde_Imap_Client_Mailbox $root, $options) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Quotas'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _getQuota(Horde_Imap_Client_Mailbox $root) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Quotas'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _getQuotaRoot(Horde_Imap_Client_Mailbox $mailbox) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Quotas'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _setACL(Horde_Imap_Client_Mailbox $mailbox, $identifier, - $options) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('ACLs'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _deleteACL(Horde_Imap_Client_Mailbox $mailbox, $identifier) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('ACLs'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _getACL(Horde_Imap_Client_Mailbox $mailbox) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('ACLs'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _listACLRights(Horde_Imap_Client_Mailbox $mailbox, - $identifier) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('ACLs'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _getMyACLRights(Horde_Imap_Client_Mailbox $mailbox) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('ACLs'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _getMetadata(Horde_Imap_Client_Mailbox $mailbox, - $entries, $options) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Metadata'); - } - - /** - * @throws Horde_Imap_Client_Exception_NoSupportPop3 - */ - protected function _setMetadata(Horde_Imap_Client_Mailbox $mailbox, $data) - { - throw new Horde_Imap_Client_Exception_NoSupportPop3('Metadata'); - } - - /** - */ - protected function _getSearchCache($type, $options) - { - /* POP3 does not support search caching. */ - return null; - } - - /** - */ - public function resolveIds(Horde_Imap_Client_Mailbox $mailbox, - Horde_Imap_Client_Ids $ids, $convert = 0) - { - if (!$ids->special && - (!$convert || - (!$ids->sequence && ($convert == 1)) || - $ids->isEmpty())) { - return clone $ids; - } - - $uids = $this->_pop3Cache('uidl'); - - return $this->getIdsOb( - $ids->all ? array_values($uids) : array_intersect_keys($uids, $ids->ids) - ); - } - - /* Internal functions. */ - - /** - * Perform a command on the server. A connection to the server must have - * already been made. - * - * @param string $cmd The command to execute. - * @param array $options Additional options: - *
-     *   - debug: (string) When debugging, send this string instead of the
-     *            actual command/data sent.
-     *            DEFAULT: Raw data output to debug stream.
-     *   - multiline: (mixed) 'array', 'none', or 'stream'.
-     * 
- * - * @return array See _getResponse(). - * - * @throws Horde_Imap_Client_Exception - */ - protected function _sendLine($cmd, $options = array()) - { - if (!empty($options['debug'])) { - $this->_debug->client($options['debug']); - } - - if ($this->_debug->debug) { - $timer = new Horde_Support_Timer(); - $timer->push(); - } - - try { - $this->_connection->write($cmd, empty($options['debug'])); - } catch (Horde_Imap_Client_Exception $e) { - throw $e; - } - - $resp = $this->_getResponse( - empty($options['multiline']) ? false : $options['multiline'] - ); - - if ($this->_debug->debug) { - $this->_debug->info(sprintf( - 'Command took %s seconds.', - round($timer->pop(), 4) - )); - } - - return $resp; - } - - /** - * Gets a line from the stream and parses it. - * - * @param mixed $multiline 'array', 'none', 'stream', or null. - * - * @return array An array with the following keys: - * - data: (mixed) Stream, array, or null. - * - resp: (string) The server response text. - * - * @throws Horde_Imap_Client_Exception - */ - protected function _getResponse($multiline = false) - { - $ob = array('resp' => ''); - - $read = explode(' ', rtrim($this->_connection->read(), "\r\n"), 2); - if (!in_array($read[0], array('+OK', '-ERR', '+'))) { - $this->_debug->info('ERROR: IMAP read/timeout error.'); - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error when communicating with the mail server."), - Horde_Imap_Client_Exception::SERVER_READERROR - ); - } - - $respcode = null; - if (isset($read[1]) && - isset($this->_init['capability']) && - $this->_capability('RESP-CODES')) { - $respcode = $this->_parseResponseCode($read[1]); - } - - switch ($read[0]) { - case '+OK': - case '+': - if ($respcode) { - $ob['resp'] = $respcode->text; - } elseif (isset($read[1])) { - $ob['resp'] = $read[1]; - } - break; - - case '-ERR': - $errcode = 0; - if ($respcode) { - $errtext = $respcode->text; - - if (isset($respcode->code)) { - switch ($respcode->code) { - // RFC 2449 [8.1.1] - case 'IN-USE': - // RFC 2449 [8.1.2] - case 'LOGIN-DELAY': - $errcode = Horde_Imap_Client_Exception::LOGIN_UNAVAILABLE; - break; - - // RFC 3206 [4] - case 'SYS/TEMP': - $errcode = Horde_Imap_Client_Exception::POP3_TEMP_ERROR; - break; - - // RFC 3206 [4] - case 'SYS/PERM': - $errcode = Horde_Imap_Client_Exception::POP3_PERM_ERROR; - break; - - // RFC 3206 [5] - case 'AUTH': - $errcode = Horde_Imap_Client_Exception::LOGIN_AUTHENTICATIONFAILED; - break; - - // RFC 6856 [5] - case 'UTF8': - /* This code can only be issued if we (as client) are - * broken, so no need to handle since we should never - * be broken. */ - break; - } - } - } elseif (isset($read[1])) { - $errtext = $read[1]; - } else { - $errtext = '[No error message provided by server]'; - } - - $e = new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("POP3 error reported by server."), - $errcode - ); - $e->details = $errtext; - throw $e; - } - - switch ($multiline) { - case 'array': - $ob['data'] = array(); - break; - - case 'none': - $ob['data'] = null; - break; - - case 'stream': - $ob['data'] = fopen('php://temp', 'r+'); - break; - - default: - return $ob; - } - - do { - $orig_read = $this->_connection->read(); - $read = rtrim($orig_read, "\r\n"); - - if ($read === '.') { - break; - } elseif (substr($read, 0, 2) === '..') { - $read = substr($read, 1); - } - - if (is_array($ob['data'])) { - $ob['data'][] = $read; - } elseif (!is_null($ob['data'])) { - fwrite($ob['data'], $orig_read); - } - } while (true); - - return $ob; - } - - /** - * Returns a list of sequence IDs. - * - * @param Horde_Imap_Client_Ids $ids The ID list. - * - * @return array A list of sequence IDs. - */ - protected function _getSeqIds(Horde_Imap_Client_Ids $ids) - { - if (!count($ids)) { - $status = $this->status($this->_selected, Horde_Imap_Client::STATUS_MESSAGES); - return range(1, $status['messages']); - } elseif ($ids->sequence) { - return $ids->ids; - } - - return array_keys(array_intersect($this->_pop3Cache('uidl'), $ids->ids)); - } - - /** - * Parses response text for response codes (RFC 2449 [8]). - * - * @param string $text The response text. - * - * @return object An object with the following properties: - * - code: (string) The response code, if it exists. - * - data: (string) The response code data, if it exists. - * - text: (string) The human-readable response text. - */ - protected function _parseResponseCode($text) - { - $ret = new stdClass; - - $text = trim($text); - if ($text[0] === '[') { - $pos = strpos($text, ' ', 2); - $end_pos = strpos($text, ']', 2); - if ($pos > $end_pos) { - $ret->code = Horde_String::upper(substr($text, 1, $end_pos - 1)); - } else { - $ret->code = Horde_String::upper(substr($text, 1, $pos - 1)); - $ret->data = substr($text, $pos + 1, $end_pos - $pos - 1); - } - $ret->text = trim(substr($text, $end_pos + 1)); - } else { - $ret->text = $text; - } - - return $ret; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Tokenize.php b/lib/horde/framework/Horde/Imap/Client/Tokenize.php deleted file mode 100644 index 33ee4c32e17..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Tokenize.php +++ /dev/null @@ -1,418 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @internal - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * - * @property-read boolean $eos Has the end of the stream been reached? - */ -class Horde_Imap_Client_Tokenize implements Iterator -{ - /** - * Current data. - * - * @var mixed - */ - protected $_current = false; - - /** - * Current key. - * - * @var integer - */ - protected $_key = false; - - /** - * Sublevel. - * - * @var integer - */ - protected $_level = false; - - /** - * Array of literal stream objects. - * - * @var array - */ - protected $_literals = array(); - - /** - * Return Horde_Stream object for literal tokens? - * - * @var boolean - */ - protected $_literalStream = false; - - /** - * next() modifiers. - * - * @var array - */ - protected $_nextModify = array(); - - /** - * Data stream. - * - * @var Horde_Stream - */ - protected $_stream; - - /** - * Constructor. - * - * @param mixed $data Data to add (string, resource, or Horde_Stream - * object). - */ - public function __construct($data = null) - { - $this->_stream = new Horde_Stream_Temp(); - - if (!is_null($data)) { - $this->add($data); - } - } - - /** - */ - public function __clone() - { - throw new LogicException('Object can not be cloned.'); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'eos': - return $this->_stream->eof(); - } - } - - /** - */ - public function __sleep() - { - throw new LogicException('Object can not be serialized.'); - } - - /** - */ - public function __toString() - { - $pos = $this->_stream->pos(); - $out = $this->_current . ' ' . $this->_stream->getString(); - $this->_stream->seek($pos, false); - return $out; - } - - /** - * Add data to buffer. - * - * @param mixed $data Data to add (string, resource, or Horde_Stream - * object). - */ - public function add($data) - { - $this->_stream->add($data); - } - - /** - * Add data to literal stream at the current position. - * - * @param mixed $data Data to add (string, resource, or Horde_Stream - * object). - */ - public function addLiteralStream($data) - { - $pos = $this->_stream->pos(); - if (!isset($this->_literals[$pos])) { - $this->_literals[$pos] = new Horde_Stream_Temp(); - } - $this->_literals[$pos]->add($data); - } - - /** - * Flush the remaining entries left in the iterator. - * - * @param boolean $return If true, return entries. Only returns entries - * on the current level. - * @param boolean $sublevel Only flush items in current sublevel? - * - * @return array The entries if $return is true. - */ - public function flushIterator($return = true, $sublevel = true) - { - $out = array(); - - if ($return) { - $this->_nextModify = array( - 'level' => $sublevel ? $this->_level : 0, - 'out' => array() - ); - $this->next(); - $out = $this->_nextModify['out']; - $this->_nextModify = array(); - } elseif ($sublevel && $this->_level) { - $this->_nextModify = array( - 'level' => $this->_level - ); - $this->next(); - $this->_nextModify = array(); - } else { - $this->_stream->end(); - $this->_stream->getChar(); - $this->_current = $this->_key = $this->_level = false; - } - - return $out; - } - - /** - * Return literal length data located at the end of the stream. - * - * @return mixed Null if no literal data found, or an array with these - * keys: - * - binary: (boolean) True if this is a literal8. - * - length: (integer) Length of the literal. - */ - public function getLiteralLength() - { - if ($this->_stream->substring(-1, 1) === '}') { - $literal_data = $this->_stream->getString( - $this->_stream->search('{', true) - 1 - ); - $literal_len = substr($literal_data, 2, -1); - - if (is_numeric($literal_len)) { - return array( - 'binary' => ($literal_data[0] === '~'), - 'length' => intval($literal_len) - ); - } - } - - return null; - } - - /* Iterator methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function current() - { - return $this->_current; - } - - /** - */ - #[ReturnTypeWillChange] - public function key() - { - return $this->_key; - } - - /** - * @return mixed Either a string, boolean (true for open paren, false for - * close paren/EOS), Horde_Stream object, or null. - */ - #[ReturnTypeWillChange] - public function next() - { - $level = isset($this->_nextModify['level']) - ? $this->_nextModify['level'] - : null; - /* Directly access stream here to drastically reduce the number of - * getChar() calls we would have to make. */ - $stream = $this->_stream->stream; - - do { - $check_len = true; - $in_quote = $text = $binary = false; - - while (($c = fgetc($stream)) !== false) { - switch ($c) { - case '\\': - $text .= $in_quote - ? fgetc($stream) - : $c; - break; - - case '"': - if ($in_quote) { - $check_len = false; - break 2; - } - $in_quote = true; - /* Set $text to non-false (could be empty string). */ - $text = ''; - break; - - default: - if ($in_quote) { - $text .= $c; - break; - } - - switch ($c) { - case '(': - ++$this->_level; - $check_len = false; - $text = true; - break 3; - - case ')': - if ($text === false) { - --$this->_level; - $check_len = $text = false; - } else { - $this->_stream->seek(-1); - } - break 3; - - case '~': - // Ignore binary string identifier. PHP strings are - // binary-safe. But keep it if it is not used as string - // identifier. - $binary = true; - $text .= $c; - continue 3; - - case '{': - if ($binary) { - $text = substr($text, 0, -1); - } - $literal_len = intval($this->_stream->getToChar('}')); - $pos = $this->_stream->pos(); - if (isset($this->_literals[$pos])) { - $text = $this->_literals[$pos]; - if (!$this->_literalStream) { - $text = strval($text); - } - } elseif ($this->_literalStream) { - $text = new Horde_Stream_Temp(); - while (($literal_len > 0) && !feof($stream)) { - $part = $this->_stream->substring( - 0, - min($literal_len, 8192) - ); - $text->add($part); - $literal_len -= strlen($part); - } - } else { - $text = $this->_stream->substring(0, $literal_len); - } - $check_len = false; - break 3; - - case ' ': - if ($text !== false) { - break 3; - } - break; - - default: - $text .= $c; - break; - } - break; - } - $binary = false; - } - - if ($check_len) { - switch (strlen($text)) { - case 0: - $text = false; - break; - - case 3: - if (strcasecmp($text, 'NIL') === 0) { - $text = null; - } - break; - } - } - - if (($text === false) && feof($stream)) { - $this->_key = $this->_level = false; - break; - } - - ++$this->_key; - - if (is_null($level) || ($level > $this->_level)) { - break; - } - - if (($level === $this->_level) && !is_bool($text)) { - $this->_nextModify['out'][] = $text; - } - } while (true); - - $this->_current = $text; - - return $text; - } - - /** - * Force return of literal data as stream, if next token. - * - * @see next() - */ - public function nextStream() - { - $changed = $this->_literalStream; - $this->_literalStream = true; - - $out = $this->next(); - - if ($changed) { - $this->_literalStream = false; - } - - return $out; - } - - /** - */ - #[ReturnTypeWillChange] - public function rewind() - { - $this->_stream->rewind(); - $this->_current = false; - $this->_key = -1; - $this->_level = 0; - } - - /** - */ - #[ReturnTypeWillChange] - public function valid() - { - return ($this->_level !== false); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Translation.php b/lib/horde/framework/Horde/Imap/Client/Translation.php deleted file mode 100644 index fdd32b316d6..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Translation.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @category Horde - * @copyright 2010-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL - * @package Imap_Client - */ -class Horde_Imap_Client_Translation extends Horde_Translation_Autodetect -{ - /** - * The translation domain - * - * @var string - */ - protected static $_domain = 'Horde_Imap_Client'; - - /** - * The absolute PEAR path to the translations for the default gettext handler. - * - * @var string - */ - protected static $_pearDirectory = '@data_dir@'; -} diff --git a/lib/horde/framework/Horde/Imap/Client/Url.php b/lib/horde/framework/Horde/Imap/Client/Url.php deleted file mode 100644 index 68d1f38cbca..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Url.php +++ /dev/null @@ -1,319 +0,0 @@ - - * @category Horde - * @copyright 2008-2016 Horde LLC - * @deprecated Use Horde_Imap_Client_Url_Base instead - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * - * @property-read boolean $relative Is this a relative URL? - */ -class Horde_Imap_Client_Url implements Serializable -{ - /** - * The authentication method to use. - * - * @var string - */ - public $auth = null; - - /** - * The remote server (not present for relative URLs). - * - * @var string - */ - public $hostspec = null; - - /** - * The IMAP mailbox. - * - * @todo Make this a Horde_Imap_Client_Mailbox object. - * - * @var string - */ - public $mailbox = null; - - /** - * A byte range for use with IMAP FETCH. - * - * @var string - */ - public $partial = null; - - /** - * The remote port (not present for relative URLs). - * - * @var integer - */ - public $port = null; - - /** - * The protocol type. Either 'imap' or 'pop' (not present for relative - * URLs). - * - * @var string - */ - public $protocol = null; - - /** - * A search query to be run with IMAP SEARCH. - * - * @var string - */ - public $search = null; - - /** - * A MIME part ID. - * - * @var string - */ - public $section = null; - - /** - * The username to use on the remote server. - * - * @var string - */ - public $username = null; - - /** - * The IMAP UID. - * - * @var string - */ - public $uid = null; - - /** - * The IMAP UIDVALIDITY for the given mailbox. - * - * @var integer - */ - public $uidvalidity = null; - - /** - * URLAUTH info (not parsed). - * - * @var string - */ - public $urlauth = null; - - /** - * Constructor. - * - * Absolute IMAP URLs takes one of the following forms: - * - imap://[/] - * - imap:///[][?] - * - imap:///[][][][] - * - * POP URLs take one of the following forms: - * - pop://;auth=@: - * - * @param string $url A URL string. - */ - public function __construct($url = null) - { - if (!is_null($url)) { - $this->_parse($url); - } - } - - /** - * Create a POP3 (RFC 2384) or IMAP (RFC 5092/5593) URL. - * - * @return string A URL string. - */ - public function __toString() - { - $url = ''; - - if (!is_null($this->protocol)) { - $url = $this->protocol . '://'; - - if (!is_null($this->username)) { - $url .= $this->username; - if (!is_null($this->auth)) { - $url .= ';AUTH=' . $this->auth; - } - $url .= '@'; - } - - $url .= $this->hostspec; - - if (!is_null($this->port)) { - switch ($this->protocol) { - case 'imap': - if ($this->port != 143) { - $url .= ':' . $this->port; - } - break; - - case 'pop': - if ($this->port != 110) { - $url .= ':' . $this->port; - } - break; - } - } - } - - $url .= '/'; - - if (is_null($this->protocol) || ($this->protocol == 'imap')) { - $url .= rawurlencode($this->mailbox); - - if (!empty($this->uidvalidity)) { - $url .= ';UIDVALIDITY=' . $this->uidvalidity; - } - - if (!is_null($this->search)) { - $url .= '?' . rawurlencode($this->search); - } else { - if (!is_null($this->uid)) { - $url .= '/;UID=' . $this->uid; - } - - if (!is_null($this->section)) { - $url .= '/;SECTION=' . $this->section; - } - - if (!is_null($this->partial)) { - $url .= '/;PARTIAL=' . $this->partial; - } - - if (!is_null($this->urlauth)) { - $url .= '/;URLAUTH=' . $this->urlauth; - } - } - } - - return $url; - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'relative': - return (is_null($this->hostspec) && - is_null($this->port) && - is_null($this->protocol)); - } - } - - /** - */ - protected function _parse($url) - { - $data = parse_url(trim($url)); - - if (isset($data['scheme'])) { - $protocol = Horde_String::lower($data['scheme']); - if (!in_array($protocol, array('imap', 'pop'))) { - return; - } - - if (isset($data['host'])) { - $this->hostspec = $data['host']; - } - $this->port = isset($data['port']) - ? $data['port'] - : (($protocol === 'imap') ? 143 : 110); - $this->protocol = $protocol; - } - - /* Check for username/auth information. */ - if (isset($data['user'])) { - if (($pos = stripos($data['user'], ';AUTH=')) !== false) { - $auth = substr($data['user'], $pos + 6); - if ($auth !== '*') { - $this->auth = $auth; - } - $data['user'] = substr($data['user'], 0, $pos); - } - - if (strlen($data['user'])) { - $this->username = $data['user']; - } - } - - /* IMAP-only information. */ - if (is_null($this->protocol) || ($this->protocol == 'imap')) { - if (isset($data['path'])) { - $data['path'] = ltrim($data['path'], '/'); - $parts = explode('/;', $data['path']); - - $mbox = array_shift($parts); - if (($pos = stripos($mbox, ';UIDVALIDITY=')) !== false) { - $this->uidvalidity = intval(substr($mbox, $pos + 13)); - $mbox = substr($mbox, 0, $pos); - } - $this->mailbox = rawurldecode($mbox); - - if (isset($data['query'])) { - $this->search = rawurldecode($data['query']); - $parts = array(); - } - } else { - $parts = array(); - } - - if (count($parts)) { - foreach ($parts as $val) { - list($k, $v) = explode('=', $val); - $property = Horde_String::lower($k); - $this->$property = $v; - } - } - } - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version changed'); - } - $this->__unserialize($data); - } - - /** - * @return array - */ - public function __serialize() - { - return array((string)$this); - } - - public function __unserialize(array $data) - { - $this->_parse($data[0]); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Url/Base.php b/lib/horde/framework/Horde/Imap/Client/Url/Base.php deleted file mode 100644 index 13742e92010..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Url/Base.php +++ /dev/null @@ -1,190 +0,0 @@ - - * @category Horde - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.25.0 - * - * @property string $auth The authentication method. - * @property string $host The server. - * @property integer $port The port. - * @property string $username The username. - */ -abstract class Horde_Imap_Client_Url_Base implements Serializable -{ - /** - * The authentication method to use. - * - * @var string - */ - protected $_auth = null; - - /** - * The server name. - * - * @var string - */ - protected $_host = null; - - /** - * The port. - * - * @var integer - */ - protected $_port = null; - - /** - * The username. - * - * @var string - */ - protected $_username = null; - - /** - * Constructor. - * - * @param string $url A URL string. - */ - public function __construct($url = null) - { - if (!is_null($url)) { - $this->_parse($url); - } - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'auth': - case 'host': - case 'port': - case 'username': - return $this->{'_' . $name}; - } - } - - /** - */ - public function __set($name, $value) - { - switch ($name) { - case 'auth': - case 'host': - case 'port': - case 'username': - $this->{'_' . $name} = $value; - break; - } - } - - /** - * Create a POP3 (RFC 2384) or IMAP (RFC 5092/5593) URL. - * - * @return string A URL string. - */ - public function __toString() - { - $url = ''; - - if (!is_null($this->username)) { - $url .= $this->username; - if (!is_null($this->auth)) { - $url .= ';AUTH=' . $this->auth; - } - $url .= '@'; - } - - $url .= $this->host; - - return $url; - } - - /** - */ - protected function _parse($url) - { - $data = parse_url(trim($url)); - - if (isset($data['scheme'])) { - if (isset($data['host'])) { - $this->host = $data['host']; - } - if (isset($data['port'])) { - $this->port = $data['port']; - } - } - - /* Check for username/auth information. */ - if (isset($data['user'])) { - if (($pos = stripos($data['user'], ';AUTH=')) !== false) { - $auth = substr($data['user'], $pos + 6); - if ($auth !== '*') { - $this->auth = $auth; - } - $data['user'] = substr($data['user'], 0, $pos); - } - - if (strlen($data['user'])) { - $this->username = $data['user']; - } - } - - $this->_parseUrl($data); - } - - /** - */ - abstract protected function _parseUrl(array $data); - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Exception('Cache version change.'); - } - $this->__unserialize($data); - } - - /** - * @return array - */ - public function __serialize() - { - return array((string)$this); - } - - public function __unserialize(array $data) - { - $this->_parse($data[0]); - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Url/Imap.php b/lib/horde/framework/Horde/Imap/Client/Url/Imap.php deleted file mode 100644 index e78c099daea..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Url/Imap.php +++ /dev/null @@ -1,230 +0,0 @@ -[/] - * - imap:///[][?] - * - imap:///[][][][] - * - * @author Michael Slusarz - * @category Horde - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.25.0 - * - * @property Horde_Imap_Client_Mailbox $mailbox IMAP Mailbox. - * @property string $partial Byte range for use with IMAP FETCH command. - * @property string $search Search query to be run with IMAP SEARCH. - * @property string $section MIME part ID. - * @property string $uid IMAP UID. - * @property string $uidvalidity IMAP UIDVALIDITY for the mailbox. - * @property string $urlauth URLAUTH info. - */ -class Horde_Imap_Client_Url_Imap extends Horde_Imap_Client_Url_Base -{ - /** - * IMAP mailbox. - * - * @var Horde_Imap_Client_Mailbox - */ - protected $_mailbox; - - /** - * Byte range for use with IMAP FETCH command. - * - * @var string - */ - protected $_partial; - - /** - * Search query to be run with IMAP SEARCH. - * - * @var string - */ - protected $_search; - - /** - * MIME part ID. - * - * @var string - */ - protected $_section; - - /** - * IMAP UID. - * - * @var string - */ - protected $_uid; - - /** - * IMAP UIDVALIDITY for the given mailbox. - * - * @var integer - */ - protected $_uidvalidity; - - /** - * URLAUTH info (not parsed). - * - * @var string - */ - protected $_urlauth; - - /** - */ - public function __get($name) - { - switch ($name) { - case 'mailbox': - return $this->_mailbox; - - case 'partial': - case 'search': - case 'section': - case 'uid': - case 'uidvalidity': - case 'urlauth': - return isset($this->{'_' . $name}) - ? $this->{'_' . $name} - : null; - - case 'port': - return parent::__get($name) ?: 143; - - default: - return parent::__get($name); - } - } - - /** - */ - public function __set($name, $value) - { - switch ($name) { - case 'mailbox': - $this->_mailbox = Horde_Imap_Client_Mailbox::get($value); - break; - - case 'partial': - case 'search': - case 'section': - case 'uid': - case 'uidvalidity': - case 'urlauth': - $this->{'_' . $name} = $value; - break; - - default: - parent::__set($name, $value); - break; - } - } - - /** - * Create an IMAP URL (RFC 5092/5593). - * - * @return string A URL string. - */ - public function __toString() - { - $url = 'imap://' . parent::__toString(); - - if (($port = $this->port) != 143) { - $url .= ':' . $port; - } - - return $url . '/' . $this->_toImapString(); - } - - /** - */ - protected function _toImapString() - { - $url = ''; - - if ($mbox = $this->mailbox) { - $url .= rawurlencode($mbox->utf7imap); - } - - if ($uidvalid = $this->uidvalidity) { - $url .= ';UIDVALIDITY=' . $uidvalid; - } - - if ($search = $this->search) { - $url .= '?' . rawurlencode($search); - } else { - if ($uid = $this->uid) { - $url .= '/;UID=' . $uid; - } - - if ($section = $this->section) { - $url .= '/;SECTION=' . $section; - } - - if ($partial = $this->partial) { - $url .= '/;PARTIAL=' . $partial; - } - - if ($urlauth = $this->urlauth) { - $url .= '/;URLAUTH=' . $urlauth; - } - } - - return $url; - } - - /** - */ - protected function _parseUrl(array $data) - { - if (isset($data['path']) && - strlen($path = ltrim($data['path'], '/'))) { - $parts = explode('/;', $path); - - $mbox = array_shift($parts); - if (($pos = stripos($mbox, ';UIDVALIDITY=')) !== false) { - $this->uidvalidity = intval(substr($mbox, $pos + 13)); - $mbox = substr($mbox, 0, $pos); - } - - if ($mbox[0] === ';') { - array_unshift($parts, substr($mbox, 1)); - } elseif (strlen($mbox)) { - $this->_mailbox = Horde_Imap_Client_Mailbox::get( - rawurldecode($mbox), - true - ); - } - - if (isset($data['query'])) { - $this->search = rawurldecode($data['query']); - $parts = array(); - } - } else { - $parts = array(); - } - - if (count($parts)) { - foreach ($parts as $val) { - list($k, $v) = explode('=', $val); - $this->{Horde_String::lower($k)} = $v; - } - } - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Url/Imap/Relative.php b/lib/horde/framework/Horde/Imap/Client/Url/Imap/Relative.php deleted file mode 100644 index 3c06d345f78..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Url/Imap/Relative.php +++ /dev/null @@ -1,45 +0,0 @@ - - * @category Horde - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.25.0 - */ -class Horde_Imap_Client_Url_Imap_Relative -extends Horde_Imap_Client_Url_Imap -{ - /** - * Create a relative IMAP URL (RFC 5092/5593). - * - * @return string A URL string. - */ - public function __toString() - { - if ($out = $this->_toImapString()) { - if (substr($out, 0, 2) === '/;') { - $out = substr($out, 1); - } elseif ($out[0] !== ';') { - $out = '/' . $out; - } - } - - return $out; - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Url/Pop3.php b/lib/horde/framework/Horde/Imap/Client/Url/Pop3.php deleted file mode 100644 index 921673bd120..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Url/Pop3.php +++ /dev/null @@ -1,64 +0,0 @@ -;auth=@: - * - * @author Michael Slusarz - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - * @since 2.25.0 - */ -class Horde_Imap_Client_Url_Pop3 extends Horde_Imap_Client_Url_Base -{ - /** - */ - public function __get($name) - { - switch ($name) { - case 'port': - return parent::__get($name) ?: 110; - - default: - return parent::__get($name); - } - } - - /** - * Create a POP3 URL (RFC 2384). - * - * @return string A URL string. - */ - public function __toString() - { - $url = 'pop://' . parent::__toString(); - - if (($port = $this->port) != 110) { - $url .= ':' . $port; - } - - return $url . '/'; - } - - /** - */ - protected function _parseUrl(array $data) - { - } - -} diff --git a/lib/horde/framework/Horde/Imap/Client/Utf7imap.php b/lib/horde/framework/Horde/Imap/Client/Utf7imap.php deleted file mode 100644 index 49833b49ada..00000000000 --- a/lib/horde/framework/Horde/Imap/Client/Utf7imap.php +++ /dev/null @@ -1,326 +0,0 @@ - - * Released under the GPL (version 2) - * - * Translated from C to PHP by Thomas Bruederli - * Code extracted from the RoundCube Webmail (http://roundcube.net) project, - * SVN revision 1757 - * The RoundCube project is released under the GPL (version 2) - * - * Copyright 2008-2017 Horde LLC (http://www.horde.org/) - * - * See the enclosed file LICENSE for license information (LGPL). If you - * did not receive this file, see http://www.horde.org/licenses/lgpl21. - * - * @category Horde - * @copyright 2000 Edmund Grimley Evans - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ - -/** - * Allows conversions between UTF-8 and UTF7-IMAP (RFC 3501 [5.1.3]). - * - * @author Michael Slusarz - * @category Horde - * @copyright 2000 Edmund Grimley Evans - * @copyright 2008-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Imap_Client - */ -class Horde_Imap_Client_Utf7imap -{ - /** - * Lookup table for conversion. - * - * @var array - */ - private static $_index64 = array( - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, 63, -1, -1, -1, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, - -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 - ); - - /** - * Lookup table for conversion. - * - * @var array - */ - private static $_base64 = array( - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', - 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', - 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', ',' - ); - - /** - * Is mbstring extension available? - * - * @var array - */ - protected static $_mbstring = null; - - /** - * Convert a string from UTF7-IMAP to UTF-8. - * - * @param string $str The UTF7-IMAP string. - * - * @return string The converted UTF-8 string. - * @throws Horde_Imap_Client_Exception - */ - public static function Utf7ImapToUtf8($str) - { - if ($str instanceof Horde_Imap_Client_Mailbox) { - return $str->utf8; - } - - $str = strval($str); - - /* Try mbstring, if available, which should be faster. Don't use the - * IMAP utf7_* functions because they are known to be buggy. */ - if (is_null(self::$_mbstring)) { - self::$_mbstring = extension_loaded('mbstring'); - } - if (self::$_mbstring) { - return @mb_convert_encoding($str, 'UTF-8', 'UTF7-IMAP'); - } - - $p = ''; - $ptr = &self::$_index64; - - for ($i = 0, $u7len = strlen($str); $u7len > 0; ++$i, --$u7len) { - $u7 = $str[$i]; - if ($u7 === '&') { - $u7 = $str[++$i]; - if (--$u7len && ($u7 === '-')) { - $p .= '&'; - continue; - } - - $ch = 0; - $k = 10; - for (; $u7len > 0; ++$i, --$u7len) { - $u7 = $str[$i]; - - if ((ord($u7) & 0x80) || ($b = $ptr[ord($u7)]) === -1) { - break; - } - - if ($k > 0) { - $ch |= $b << $k; - $k -= 6; - } else { - $ch |= $b >> (-$k); - if ($ch < 0x80) { - /* Printable US-ASCII */ - if ((0x20 <= $ch) && ($ch < 0x7f)) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), - Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION - ); - } - $p .= chr($ch); - } else if ($ch < 0x800) { - $p .= chr(0xc0 | ($ch >> 6)) . - chr(0x80 | ($ch & 0x3f)); - } else { - $p .= chr(0xe0 | ($ch >> 12)) . - chr(0x80 | (($ch >> 6) & 0x3f)) . - chr(0x80 | ($ch & 0x3f)); - } - - $ch = ($b << (16 + $k)) & 0xffff; - $k += 10; - } - } - - /* Non-zero or too many extra bits -OR- - * Base64 not properly terminated -OR- - * Adjacent Base64 sections. */ - if (($ch || ($k < 6)) || - (!$u7len || $u7 !== '-') || - (($u7len > 2) && - ($str[$i + 1] === '&') && - ($str[$i + 2] !== '-'))) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), - Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION - ); - } - } elseif ((ord($u7) < 0x20) || (ord($u7) >= 0x7f)) { - /* Not printable US-ASCII */ - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), - Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION - ); - } else { - $p .= $u7; - } - } - - return $p; - } - - /** - * Convert a string from UTF-8 to UTF7-IMAP. - * - * @param string $str The UTF-8 string. - * @param boolean $force Assume $str is UTF-8 (no-autodetection)? If - * false, attempts to auto-detect if string is - * already in UTF7-IMAP. - * - * @return string The converted UTF7-IMAP string. - * @throws Horde_Imap_Client_Exception - */ - public static function Utf8ToUtf7Imap($str, $force = true) - { - if ($str instanceof Horde_Imap_Client_Mailbox) { - return $str->utf7imap; - } - - $str = strval($str); - - /* No need to do conversion if all chars are in US-ASCII range or if - * no ampersand is present. But will assume that an already encoded - * ampersand means string is in UTF7-IMAP already. */ - if (!$force && - !preg_match('/[\x80-\xff]|&$|&(?![,+A-Za-z0-9]*-)/', $str)) { - return $str; - } - - /* Try mbstring, if available, which should be faster. Don't use the - * IMAP utf7_* functions because they are known to be buggy. */ - if (is_null(self::$_mbstring)) { - self::$_mbstring = extension_loaded('mbstring'); - } - if (self::$_mbstring) { - return @mb_convert_encoding($str, 'UTF7-IMAP', 'UTF-8'); - } - - $u8len = strlen($str); - $i = 0; - $base64 = false; - $p = ''; - $ptr = &self::$_base64; - - while ($u8len) { - $u8 = $str[$i]; - $c = ord($u8); - - if ($c < 0x80) { - $ch = $c; - $n = 0; - } elseif ($c < 0xc2) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), - Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION - ); - } elseif ($c < 0xe0) { - $ch = $c & 0x1f; - $n = 1; - } elseif ($c < 0xf0) { - $ch = $c & 0x0f; - $n = 2; - } elseif ($c < 0xf8) { - $ch = $c & 0x07; - $n = 3; - } elseif ($c < 0xfc) { - $ch = $c & 0x03; - $n = 4; - } elseif ($c < 0xfe) { - $ch = $c & 0x01; - $n = 5; - } else { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), - Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION - ); - } - - if ($n > --$u8len) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), - Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION - ); - } - - ++$i; - - for ($j = 0; $j < $n; ++$j) { - $o = ord($str[$i + $j]); - if (($o & 0xc0) !== 0x80) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), - Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION - ); - } - $ch = ($ch << 6) | ($o & 0x3f); - } - - if (($n > 1) && !($ch >> ($n * 5 + 1))) { - throw new Horde_Imap_Client_Exception( - Horde_Imap_Client_Translation::r("Error converting UTF7-IMAP string."), - Horde_Imap_Client_Exception::UTF7IMAP_CONVERSION - ); - } - - $i += $n; - $u8len -= $n; - - if (($ch < 0x20) || ($ch >= 0x7f)) { - if (!$base64) { - $p .= '&'; - $base64 = true; - $b = 0; - $k = 10; - } - - if ($ch & ~0xffff) { - $ch = 0xfffe; - } - - $p .= $ptr[($b | $ch >> $k)]; - $k -= 6; - for (; $k >= 0; $k -= 6) { - $p .= $ptr[(($ch >> $k) & 0x3f)]; - } - - $b = ($ch << (-$k)) & 0x3f; - $k += 16; - } else { - if ($base64) { - if ($k > 10) { - $p .= $ptr[$b]; - } - $p .= '-'; - $base64 = false; - } - - $p .= chr($ch); - if (chr($ch) === '&') { - $p .= '-'; - } - } - } - - if ($base64) { - if ($k > 10) { - $p .= $ptr[$b]; - } - $p .= '-'; - } - - return $p; - } - -} diff --git a/lib/horde/framework/Horde/Mail/Exception.php b/lib/horde/framework/Horde/Mail/Exception.php deleted file mode 100644 index 2b540dbbdea..00000000000 --- a/lib/horde/framework/Horde/Mail/Exception.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @category Horde - * @copyright 2010-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Exception extends Horde_Exception_Wrapped -{ -} diff --git a/lib/horde/framework/Horde/Mail/Mbox/Parse.php b/lib/horde/framework/Horde/Mail/Mbox/Parse.php deleted file mode 100644 index 6b4d6e13ceb..00000000000 --- a/lib/horde/framework/Horde/Mail/Mbox/Parse.php +++ /dev/null @@ -1,262 +0,0 @@ - - * @category Horde - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - * @since 2.5.0 - */ -class Horde_Mail_Mbox_Parse -implements ArrayAccess, Countable, Iterator -{ - /** - * Data stream. - * - * @var resource - */ - protected $_data; - - /** - * Parsed data. Each entry is an array containing 3 keys: - * - date: (mixed) Date information, in DateTime object. Null if date - * cannot be parsed. False if message is not MBOX data. - * - start: (integer) Start boundary. - * - * @var array - */ - protected $_parsed = array(); - - /** - * Constructor. - * - * @param mixed $data The mbox data. Either a resource or a filename - * as interpreted by fopen() (string). - * @param integer $limit Limit to this many messages; additional messages - * will throw an exception. - * - * @throws Horde_Mail_Parse_Exception - */ - public function __construct($data, $limit = null) - { - $this->_data = is_resource($data) - ? $data - : @fopen($data, 'r'); - - if ($this->_data === false) { - throw new Horde_Mail_Exception( - Horde_Mail_Translation::t("Could not parse mailbox data.") - ); - } - - rewind($this->_data); - - $i = 0; - $last_line = null; - /* Is this a MBOX format file? */ - $mbox = false; - - while (!feof($this->_data)) { - if (is_null($last_line)) { - $start = ftell($this->_data); - } - - $line = fgets($this->_data); - - if (is_null($last_line)) { - ltrim($line); - } - - if (substr($line, 0, 5) == 'From ') { - if (is_null($last_line)) { - /* This file is in MBOX format. */ - $mbox = true; - } elseif (!$mbox || (trim($last_line) !== '')) { - continue; - } - - if ($limit && ($i++ > $limit)) { - throw new Horde_Mail_Exception( - sprintf( - Horde_Mail_Translation::t("Imported mailbox contains more than enforced limit of %u messages."), - $limit - ) - ); - } - - $from_line = explode(' ', $line, 3); - try { - $date = new DateTime($from_line[2]); - } catch (Exception $e) { - $date = null; - } - - $this->_parsed[] = array( - 'date' => $date, - 'start' => ftell($this->_data) - ); - } - - /* Strip all empty lines before first data. */ - if (!is_null($last_line) || (trim($line) !== '')) { - $last_line = $line; - } - } - - /* This was a single message, not a MBOX file. */ - if (empty($this->_parsed)) { - $this->_parsed[] = array( - 'date' => false, - 'start' => $start - ); - } - } - - /* ArrayAccess methods. */ - - /** - */ - #[\ReturnTypeWillChange] - public function offsetExists($offset) - { - return isset($this->_parsed[$offset]); - } - - /** - */ - #[\ReturnTypeWillChange] - public function offsetGet($offset) - { - if (!isset($this->_parsed[$offset])) { - return null; - } - - $p = $this->_parsed[$offset]; - $end = isset($this->_parsed[$offset + 1]) - ? $this->_parsed[$offset + 1]['start'] - : null; - $fd = fopen('php://temp', 'w+'); - - fseek($this->_data, $p['start']); - while (!feof($this->_data)) { - $line = fgets($this->_data); - if ($end && (ftell($this->_data) >= $end)) { - break; - } - - fwrite( - $fd, - (($p['date'] !== false) && substr($line, 0, 6) == '>From ') - ? substr($line, 1) - : $line - ); - } - - $out = array( - 'data' => $fd, - 'date' => ($p['date'] === false) ? null : $p['date'], - 'size' => intval(ftell($fd)) - ); - rewind($fd); - - return $out; - } - - /** - */ - #[\ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - // NOOP - } - - /** - */ - #[\ReturnTypeWillChange] - public function offsetUnset($offset) - { - // NOOP - } - - /* Countable methods. */ - - /** - * Index count. - * - * @return integer The number of messages. - */ - #[\ReturnTypeWillChange] - public function count() - { - return count($this->_parsed); - } - - /* Magic methods. */ - - /** - * String representation of the object. - * - * @return string String representation. - */ - public function __toString() - { - rewind($this->_data); - return stream_get_contents($this->_data); - } - - /* Iterator methods. */ - - #[\ReturnTypeWillChange] - public function current() - { - $key = $this->key(); - - return is_null($key) - ? null - : $this[$key]; - } - - #[\ReturnTypeWillChange] - public function key() - { - return key($this->_parsed); - } - - #[\ReturnTypeWillChange] - public function next() - { - if ($this->valid()) { - next($this->_parsed); - } - } - - #[\ReturnTypeWillChange] - public function rewind() - { - reset($this->_parsed); - } - - #[\ReturnTypeWillChange] - public function valid() - { - return !is_null($this->key()); - } - -} diff --git a/lib/horde/framework/Horde/Mail/Rfc822.php b/lib/horde/framework/Horde/Mail/Rfc822.php deleted file mode 100644 index a6ea2f42fec..00000000000 --- a/lib/horde/framework/Horde/Mail/Rfc822.php +++ /dev/null @@ -1,896 +0,0 @@ - - * - * @category Horde - * @copyright 2001-2010 Richard Heyes - * @copyright 2002-2011 Timo Sirainen - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ - -/** - * RFC 822/2822/3490/5322 Email parser/validator. - * - * @author Richard Heyes - * @author Chuck Hagenbuch - * @author Michael Slusarz - * @author Timo Sirainen - * @category Horde - * @copyright 2001-2010 Richard Heyes - * @copyright 2002-2011 Timo Sirainen - * @copyright 2011-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Rfc822 -{ - /** - * Valid atext characters. - * - * @deprecated - * @since 2.0.3 - */ - const ATEXT = '!#$%&\'*+-./0123456789=?ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~'; - - /** - * Excluded (in ASCII decimal): 0-8, 10-31, 34, 40-41, 44, 58-60, 62, 64, - * 91-93, 127 - * - * @since 2.0.3 - */ - const ENCODE_FILTER = "\0\1\2\3\4\5\6\7\10\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\"(),:;<>@[\\]\177"; - - /** - * The address string to parse. - * - * @var string - */ - protected $_data; - - /** - * Length of the address string. - * - * @var integer - */ - protected $_datalen; - - /** - * Comment cache. - * - * @var string - */ - protected $_comments = array(); - - /** - * List object to return in parseAddressList(). - * - * @var Horde_Mail_Rfc822_List - */ - protected $_listob; - - /** - * Configuration parameters. - * - * @var array - */ - protected $_params = array(); - - /** - * Data pointer. - * - * @var integer - */ - protected $_ptr; - - /** - * Starts the whole process. - * - * @param mixed $address The address(es) to validate. Either a string, - * a Horde_Mail_Rfc822_Object, or an array of - * strings and/or Horde_Mail_Rfc822_Objects. - * @param array $params Optional parameters: - * - default_domain: (string) Default domain/host. - * DEFAULT: None - * - group: (boolean) Return a GroupList object instead of a List object? - * DEFAULT: false - * - limit: (integer) Stop processing after this many addresses. - * DEFAULT: No limit (0) - * - validate: (mixed) Strict validation of personal part data? If - * false, attempts to allow non-ASCII characters and - * non-quoted strings in the personal data, and will - * silently abort if an unparseable address is found. - * If true, does strict RFC 5322 (ASCII-only) parsing. If - * 'eai' (@since 2.5.0), allows RFC 6532 (EAI/UTF-8) - * addresses. - * DEFAULT: false - * - * @return Horde_Mail_Rfc822_List A list object. - * - * @throws Horde_Mail_Exception - */ - public function parseAddressList($address, array $params = array()) - { - if ($address instanceof Horde_Mail_Rfc822_List) { - return $address; - } - - if (empty($params['limit'])) { - $params['limit'] = -1; - } - - $this->_params = array_merge(array( - 'default_domain' => null, - 'validate' => false - ), $params); - - $this->_listob = empty($this->_params['group']) - ? new Horde_Mail_Rfc822_List() - : new Horde_Mail_Rfc822_GroupList(); - - if (!is_array($address)) { - $address = array($address); - } - - $tmp = array(); - foreach ($address as $val) { - if ($val instanceof Horde_Mail_Rfc822_Object) { - $this->_listob->add($val); - } else { - $tmp[] = rtrim(trim($val), ','); - } - } - - if (!empty($tmp)) { - $this->_data = implode(',', $tmp); - $this->_datalen = strlen($this->_data); - $this->_ptr = 0; - - $this->_parseAddressList(); - } - - $ret = $this->_listob; - unset($this->_listob); - - return $ret; - } - - /** - * Quotes and escapes the given string if necessary using rules contained - * in RFC 2822 [3.2.5]. - * - * @param string $str The string to be quoted and escaped. - * @param string $type Either 'address', 'comment' (@since 2.6.0), or - * 'personal'. - * - * @return string The correctly quoted and escaped string. - */ - public function encode($str, $type = 'address') - { - switch ($type) { - case 'comment': - // RFC 5322 [3.2.2]: Filter out non-printable US-ASCII and ( ) \ - $filter = "\0\1\2\3\4\5\6\7\10\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\50\51\134\177"; - break; - - case 'personal': - // RFC 2822 [3.4]: Period not allowed in display name - $filter = self::ENCODE_FILTER . '.'; - break; - - case 'address': - default: - // RFC 2822 [3.4.1]: (HTAB, SPACE) not allowed in address - $filter = self::ENCODE_FILTER . "\11\40"; - break; - } - - // Strip double quotes if they are around the string already. - // If quoted, we know that the contents are already escaped, so - // unescape now. - $str = trim($str); - if ($str && ($str[0] === '"') && (substr($str, -1) === '"')) { - $str = stripslashes(substr($str, 1, -1)); - } - - return (strcspn($str, $filter) != strlen($str)) - ? '"' . addcslashes($str, '\\"') . '"' - : $str; - } - - /** - * If an email address has no personal information, get rid of any angle - * brackets (<>) around it. - * - * @param string $address The address to trim. - * - * @return string The trimmed address. - */ - public function trimAddress($address) - { - $address = trim($address); - - return (($address[0] == '<') && (substr($address, -1) == '>')) - ? substr($address, 1, -1) - : $address; - } - - /* RFC 822 parsing methods. */ - - /** - * address-list = (address *("," address)) / obs-addr-list - */ - protected function _parseAddressList() - { - $limit = $this->_params['limit']; - - while (($this->_curr() !== false) && ($limit-- !== 0)) { - try { - $this->_parseAddress(); - } catch (Horde_Mail_Exception $e) { - if ($this->_params['validate']) { - throw $e; - } - ++$this->_ptr; - } - - switch ($this->_curr()) { - case ',': - $this->_rfc822SkipLwsp(true); - break; - - case false: - // No-op - break; - - default: - if ($this->_params['validate']) { - throw new Horde_Mail_Exception('Error when parsing address list.'); - } - break; - } - } - } - - /** - * address = mailbox / group - */ - protected function _parseAddress() - { - $start = $this->_ptr; - if (!$this->_parseGroup()) { - $this->_ptr = $start; - if ($mbox = $this->_parseMailbox()) { - $this->_listob->add($mbox); - } - } - } - - /** - * group = display-name ":" [mailbox-list / CFWS] ";" [CFWS] - * display-name = phrase - * - * @return boolean True if a group was parsed. - * - * @throws Horde_Mail_Exception - */ - protected function _parseGroup() - { - $this->_rfc822ParsePhrase($groupname); - - if ($this->_curr(true) != ':') { - return false; - } - - $addresses = new Horde_Mail_Rfc822_GroupList(); - - $this->_rfc822SkipLwsp(); - - while (($chr = $this->_curr()) !== false) { - if ($chr == ';') { - ++$this->_ptr; - - if (count($addresses)) { - $this->_listob->add(new Horde_Mail_Rfc822_Group($groupname, $addresses)); - } - - return true; - } - - /* mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list */ - $addresses->add($this->_parseMailbox()); - - switch ($this->_curr()) { - case ',': - $this->_rfc822SkipLwsp(true); - break; - - case ';': - // No-op - break; - - default: - break 2; - } - } - - throw new Horde_Mail_Exception('Error when parsing group.'); - } - - /** - * mailbox = name-addr / addr-spec - * - * @return mixed Mailbox object if mailbox was parsed, or false. - */ - protected function _parseMailbox() - { - $this->_comments = array(); - $start = $this->_ptr; - - if (!($ob = $this->_parseNameAddr())) { - $this->_comments = array(); - $this->_ptr = $start; - $ob = $this->_parseAddrSpec(); - } - - if ($ob) { - $ob->comment = $this->_comments; - } - - return $ob; - } - - /** - * name-addr = [display-name] angle-addr - * display-name = phrase - * - * @return mixed Mailbox object, or false. - */ - protected function _parseNameAddr() - { - $this->_rfc822ParsePhrase($personal); - - if ($ob = $this->_parseAngleAddr()) { - $ob->personal = $personal; - return $ob; - } - - return false; - } - - /** - * addr-spec = local-part "@" domain - * - * @return mixed Mailbox object. - * - * @throws Horde_Mail_Exception - */ - protected function _parseAddrSpec() - { - $ob = new Horde_Mail_Rfc822_Address(); - $ob->mailbox = $this->_parseLocalPart(); - - if ($this->_curr() == '@') { - try { - $this->_rfc822ParseDomain($host); - if (!empty($host)) { - $ob->host = $host; - } - } catch (Horde_Mail_Exception $e) { - if (!empty($this->_params['validate'])) { - throw $e; - } - } - } - - if (is_null($ob->host)) { - if (!is_null($this->_params['default_domain'])) { - $ob->host = $this->_params['default_domain']; - } elseif (!empty($this->_params['validate'])) { - throw new Horde_Mail_Exception('Address is missing domain.'); - } - } - - return $ob; - } - - /** - * local-part = dot-atom / quoted-string / obs-local-part - * obs-local-part = word *("." word) - * - * @return string The local part. - * - * @throws Horde_Mail_Exception - */ - protected function _parseLocalPart() - { - if (($curr = $this->_curr()) === false) { - throw new Horde_Mail_Exception('Error when parsing local part.'); - } - - if ($curr == '"') { - $this->_rfc822ParseQuotedString($str); - } else { - $this->_rfc822ParseDotAtom($str, ',;@'); - } - - return $str; - } - - /** - * "<" [ "@" route ":" ] local-part "@" domain ">" - * - * @return mixed Mailbox object, or false. - * - * @throws Horde_Mail_Exception - */ - protected function _parseAngleAddr() - { - if ($this->_curr() != '<') { - return false; - } - - $this->_rfc822SkipLwsp(true); - - if ($this->_curr() == '@') { - // Route information is ignored. - $this->_parseDomainList(); - if ($this->_curr() != ':') { - throw new Horde_Mail_Exception('Invalid route.'); - } - - $this->_rfc822SkipLwsp(true); - } - - $ob = $this->_parseAddrSpec(); - - if ($this->_curr() != '>') { - throw new Horde_Mail_Exception('Error when parsing angle address.'); - } - - $this->_rfc822SkipLwsp(true); - - return $ob; - } - - /** - * obs-domain-list = "@" domain *(*(CFWS / "," ) [CFWS] "@" domain) - * - * @return array Routes. - * - * @throws Horde_Mail_Exception - */ - protected function _parseDomainList() - { - $route = array(); - - while ($this->_curr() !== false) { - $this->_rfc822ParseDomain($str); - $route[] = '@' . $str; - - $this->_rfc822SkipLwsp(); - if ($this->_curr() != ',') { - return $route; - } - ++$this->_ptr; - } - - throw new Horde_Mail_Exception('Invalid domain list.'); - } - - /* RFC 822 parsing methods. */ - - /** - * phrase = 1*word / obs-phrase - * word = atom / quoted-string - * obs-phrase = word *(word / "." / CFWS) - * - * @param string &$phrase The phrase data. - * - * @throws Horde_Mail_Exception - */ - protected function _rfc822ParsePhrase(&$phrase) - { - $curr = $this->_curr(); - if (($curr === false) || ($curr == '.')) { - throw new Horde_Mail_Exception('Error when parsing a group.'); - } - - do { - if ($curr == '"') { - $this->_rfc822ParseQuotedString($phrase); - } else { - $this->_rfc822ParseAtomOrDot($phrase); - } - - $curr = $this->_curr(); - if (($curr != '"') && - ($curr != '.') && - !$this->_rfc822IsAtext($curr)) { - break; - } - - $phrase .= ' '; - } while ($this->_ptr < $this->_datalen); - - $this->_rfc822SkipLwsp(); - } - - /** - * @param string &$phrase The quoted string data. - * - * @throws Horde_Mail_Exception - */ - protected function _rfc822ParseQuotedString(&$str) - { - if ($this->_curr(true) != '"') { - throw new Horde_Mail_Exception('Error when parsing a quoted string.'); - } - - while (($chr = $this->_curr(true)) !== false) { - switch ($chr) { - case '"': - $this->_rfc822SkipLwsp(); - return; - - case "\n": - /* Folding whitespace, remove the (CR)LF. */ - if (substr($str, -1) == "\r") { - $str = substr($str, 0, -1); - } - continue 2; - - case '\\': - if (($chr = $this->_curr(true)) === false) { - break 2; - } - break; - } - - $str .= $chr; - } - - /* Missing trailing '"', or partial quoted character. */ - throw new Horde_Mail_Exception('Error when parsing a quoted string.'); - } - - /** - * dot-atom = [CFWS] dot-atom-text [CFWS] - * dot-atom-text = 1*atext *("." 1*atext) - * - * atext = ; Any character except controls, SP, and specials. - * - * For RFC-822 compatibility allow LWSP around '.'. - * - * - * @param string &$str The atom/dot data. - * @param string $validate Use these characters as delimiter. - * - * @throws Horde_Mail_Exception - */ - protected function _rfc822ParseDotAtom(&$str, $validate = null) - { - $valid = false; - - while ($this->_ptr < $this->_datalen) { - $chr = $this->_data[$this->_ptr]; - - /* TODO: Optimize by duplicating rfc822IsAtext code here */ - if ($this->_rfc822IsAtext($chr, $validate)) { - $str .= $chr; - ++$this->_ptr; - } elseif (!$valid) { - throw new Horde_Mail_Exception('Error when parsing dot-atom.'); - } else { - $this->_rfc822SkipLwsp(); - - if ($this->_curr() != '.') { - return; - } - $str .= $chr; - - $this->_rfc822SkipLwsp(true); - } - - $valid = true; - } - } - - /** - * atom = [CFWS] 1*atext [CFWS] - * atext = ; Any character except controls, SP, and specials. - * - * This method doesn't just silently skip over WS. - * - * @param string &$str The atom/dot data. - * - * @throws Horde_Mail_Exception - */ - protected function _rfc822ParseAtomOrDot(&$str) - { - while ($this->_ptr < $this->_datalen) { - $chr = $this->_data[$this->_ptr]; - if (($chr != '.') && - /* TODO: Optimize by duplicating rfc822IsAtext code here */ - !$this->_rfc822IsAtext($chr, ',<:')) { - $this->_rfc822SkipLwsp(); - if (!$this->_params['validate'] && $str !== null) { - $str = trim($str); - } - return; - } - - $str .= $chr; - ++$this->_ptr; - } - } - - /** - * domain = dot-atom / domain-literal / obs-domain - * domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS] - * obs-domain = atom *("." atom) - * - * @param string &$str The domain string. - * - * @throws Horde_Mail_Exception - */ - protected function _rfc822ParseDomain(&$str) - { - if ($this->_curr(true) != '@') { - throw new Horde_Mail_Exception('Error when parsing domain.'); - } - - $this->_rfc822SkipLwsp(); - - if ($this->_curr() == '[') { - $this->_rfc822ParseDomainLiteral($str); - } else { - $this->_rfc822ParseDotAtom($str, ';,> '); - } - } - - /** - * domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS] - * dcontent = dtext / quoted-pair - * dtext = NO-WS-CTL / ; Non white space controls - * %d33-90 / ; The rest of the US-ASCII - * %d94-126 ; characters not including "[", - * ; "]", or "\" - * - * @param string &$str The domain string. - * - * @throws Horde_Mail_Exception - */ - protected function _rfc822ParseDomainLiteral(&$str) - { - if ($this->_curr(true) != '[') { - throw new Horde_Mail_Exception('Error parsing domain literal.'); - } - - while (($chr = $this->_curr(true)) !== false) { - switch ($chr) { - case '\\': - if (($chr = $this->_curr(true)) === false) { - break 2; - } - break; - - case ']': - $this->_rfc822SkipLwsp(); - return; - } - - $str .= $chr; - } - - throw new Horde_Mail_Exception('Error parsing domain literal.'); - } - - /** - * @param boolean $advance Advance cursor? - * - * @throws Horde_Mail_Exception - */ - protected function _rfc822SkipLwsp($advance = false) - { - if ($advance) { - ++$this->_ptr; - } - - while (($chr = $this->_curr()) !== false) { - switch ($chr) { - case ' ': - case "\n": - case "\r": - case "\t": - ++$this->_ptr; - continue 2; - - case '(': - $this->_rfc822SkipComment(); - break; - - default: - return; - } - } - } - - /** - * @throws Horde_Mail_Exception - */ - protected function _rfc822SkipComment() - { - if ($this->_curr(true) != '(') { - throw new Horde_Mail_Exception('Error when parsing a comment.'); - } - - $comment = ''; - $level = 1; - - while (($chr = $this->_curr(true)) !== false) { - switch ($chr) { - case '(': - ++$level; - continue 2; - - case ')': - if (--$level == 0) { - $this->_comments[] = $comment; - return; - } - break; - - case '\\': - if (($chr = $this->_curr(true)) === false) { - break 2; - } - break; - } - - $comment .= $chr; - } - - throw new Horde_Mail_Exception('Error when parsing a comment.'); - } - - /** - * Check if data is an atom. - * - * @param string $chr The character to check. - * @param string $validate If in non-validate mode, use these characters - * as the non-atom delimiters. - * - * @return boolean True if a valid atom. - */ - protected function _rfc822IsAtext($chr, $validate = null) - { - if (!$this->_params['validate'] && !is_null($validate)) { - return strcspn($chr, $validate); - } - - $ord = ord($chr); - - /* UTF-8 characters check. */ - if ($ord > 127) { - return ($this->_params['validate'] === 'eai'); - } - - /* Check for DISALLOWED characters under both RFCs 5322 and 6532. */ - - /* Unprintable characters && [SPACE] */ - if ($ord <= 32) { - return false; - } - - /* "(),:;<>@[\] [DEL] */ - switch ($ord) { - case 34: - case 40: - case 41: - case 44: - case 58: - case 59: - case 60: - case 62: - case 64: - case 91: - case 92: - case 93: - case 127: - return false; - } - - return true; - } - - /* Helper methods. */ - - /** - * Return current character. - * - * @param boolean $advance If true, advance the cursor. - * - * @return string The current character (false if EOF reached). - */ - protected function _curr($advance = false) - { - return ($this->_ptr >= $this->_datalen) - ? false - : $this->_data[$advance ? $this->_ptr++ : $this->_ptr]; - } - - /* Other public methods. */ - - /** - * Returns an approximate count of how many addresses are in the string. - * This is APPROXIMATE as it only splits based on a comma which has no - * preceding backslash. - * - * @param string $data Addresses to count. - * - * @return integer Approximate count. - */ - public function approximateCount($data) - { - return count(preg_split('/(?@. This can be sufficient for most people. - * - * Optional stricter mode can be utilized which restricts mailbox - * characters allowed to: alphanumeric, full stop, hyphen, and underscore. - * - * @param string $data Address to check. - * @param boolean $strict Strict check? - * - * @return mixed False if it fails, an indexed array username/domain if - * it matches. - */ - public function isValidInetAddress($data, $strict = false) - { - $regex = $strict - ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' - : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i'; - - return preg_match($regex, trim($data), $matches) - ? array($matches[1], $matches[2]) - : false; - } - -} diff --git a/lib/horde/framework/Horde/Mail/Rfc822/Address.php b/lib/horde/framework/Horde/Mail/Rfc822/Address.php deleted file mode 100644 index 22c429c964f..00000000000 --- a/lib/horde/framework/Horde/Mail/Rfc822/Address.php +++ /dev/null @@ -1,242 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - * - * @property-read string $bare_address The bare mailbox@host address. - * @property-read string $bare_address_idn The bare mailbox@host address (IDN - * encoded). (@since 2.1.0) - * @property-read boolean $eai Returns true if the local (mailbox) address - * part requires EAI (UTF-8) support. - * (@since 2.5.0) - * @property-read string $encoded The full MIME/IDN encoded address (UTF-8). - * @property string $host Returns the host part (UTF-8). - * @property-read string $host_idn Returns the IDN encoded host part. - * @property-read string $label The shorthand label for this address. - * @property string $personal The personal part (UTF-8). - * @property-read string $personal_encoded The MIME encoded personal part - * (UTF-8). - * @property-read boolean $valid Returns true if there is enough information - * in object to create a valid address. - */ -class Horde_Mail_Rfc822_Address extends Horde_Mail_Rfc822_Object -{ - /** - * Comments associated with the personal phrase. - * - * @var array - */ - public $comment = array(); - - /** - * Local-part of the address (UTF-8). - * - * @var string - */ - public $mailbox = null; - - /** - * Hostname of the address. - * - * @var string - */ - protected $_host = null; - - /** - * Personal part of the address. - * - * @var string - */ - protected $_personal = null; - - /** - * Constructor. - * - * @param string $address If set, address is parsed and used as the - * object address. Address is not validated; - * first e-mail address parsed is used. - */ - public function __construct($address = null) - { - if (!is_null($address)) { - $rfc822 = new Horde_Mail_Rfc822(); - $addr = $rfc822->parseAddressList($address); - if (count($addr)) { - foreach ($addr[0] as $key => $val) { - $this->$key = $val; - } - } - } - } - - /** - */ - 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 = !empty($value) - ? Horde_Mime::decode($value) - : null; - break; - } - } - - /** - * @throws Horde_Idna_Exception - */ - public function __get($name) - { - switch ($name) { - case 'bare_address': - return is_null($this->host) - ? $this->mailbox - : $this->mailbox . '@' . $this->host; - - case 'bare_address_idn': - $personal = $this->_personal; - $this->_personal = null; - $res = $this->encoded; - $this->_personal = $personal; - return $res; - - case 'eai': - return is_null($this->mailbox) - ? false - : Horde_Mime::is8bit($this->mailbox); - - case 'encoded': - return $this->writeAddress(true); - - case 'host': - return $this->_host; - - case 'host_idn': - return Horde_Idna::encode($this->_host); - - case 'label': - return is_null($this->personal) - ? $this->bare_address - : $this->_personal; - - case 'personal': - return $this->_personal === null || (strcasecmp($this->_personal, $this->bare_address) === 0) - ? null - : $this->_personal; - - case 'personal_encoded': - return Horde_Mime::encode($this->personal); - - case 'valid': - return !empty($this->mailbox); - } - } - - /** - */ - protected function _writeAddress($opts) - { - $rfc822 = new Horde_Mail_Rfc822(); - - $address = $rfc822->encode($this->mailbox, 'address'); - $host = empty($opts['idn']) ? $this->host : $this->host_idn; - if (!empty($host)) { - $address .= '@' . $host; - } - $personal = $this->personal; - if (!empty($personal)) { - if (!empty($opts['encode'])) { - $personal = Horde_Mime::encode($this->personal, $opts['encode']); - } - if (empty($opts['noquote'])) { - $personal = $rfc822->encode($personal, 'personal'); - } - } - if (!empty($opts['comment']) && !empty($this->comment)) { - foreach ($this->comment as $val) { - $personal .= ' (' . $rfc822->encode($val, 'comment') . ')'; - } - } - - return (!empty($personal) && ($personal != $address)) - ? ltrim($personal) . ' <' . $address . '>' - : $address; - } - - /** - */ - public function match($ob) - { - if (!($ob instanceof Horde_Mail_Rfc822_Address)) { - $ob = new Horde_Mail_Rfc822_Address($ob); - } - - return ($this->bare_address == $ob->bare_address); - } - - /** - * Do a case-insensitive match on the address. Per RFC 822/2822/5322, - * although the host portion of an address is case-insensitive, the - * mailbox portion is platform dependent. - * - * @param mixed $ob Address data. - * - * @return boolean True if the data reflects the same case-insensitive - * address. - */ - public function matchInsensitive($ob) - { - if (!($ob instanceof Horde_Mail_Rfc822_Address)) { - $ob = new Horde_Mail_Rfc822_Address($ob); - } - - return (Horde_String::lower($this->bare_address) == Horde_String::lower($ob->bare_address)); - } - - /** - * Do a case-insensitive match on the address for a given domain. - * Matches as many parts of the subdomain in the address as is given in - * the input. - * - * @param string $domain Domain to match. - * - * @return boolean True if the address matches the given domain. - */ - public function matchDomain($domain) - { - $host = $this->host; - if (is_null($host)) { - return false; - } - - $match_domain = explode('.', $domain); - $match_host = array_slice(explode('.', $host), count($match_domain) * -1); - - return (strcasecmp($domain, implode('.', $match_host)) === 0); - } - -} diff --git a/lib/horde/framework/Horde/Mail/Rfc822/Group.php b/lib/horde/framework/Horde/Mail/Rfc822/Group.php deleted file mode 100644 index 638c1b17e68..00000000000 --- a/lib/horde/framework/Horde/Mail/Rfc822/Group.php +++ /dev/null @@ -1,146 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - * - * @property string $groupname Groupname (UTF-8). - * @property-read string $groupname_encoded MIME encoded groupname (UTF-8). - * @property-read string $label The shorthand label for this group. - * @property-read boolean $valid Returns true if there is enough information - * in object to create a valid address. - */ -class Horde_Mail_Rfc822_Group - extends Horde_Mail_Rfc822_Object - implements Countable -{ - /** - * List of group e-mail address objects. - * - * @var Horde_Mail_Rfc822_GroupList - */ - public $addresses; - - /** - * Group name (MIME decoded). - * - * @var string - */ - protected $_groupname = 'Group'; - - /** - * Constructor. - * - * @param string $groupname If set, used as the group name. - * @param mixed $addresses If a GroupList object, used as the address - * list. Any other non-null value is parsed and - * used as the address list (addresses not - * verified; sub-groups are ignored). - */ - public function __construct($groupname = null, $addresses = null) - { - if (!is_null($groupname)) { - $this->groupname = $groupname; - } - - if (is_null($addresses)) { - $this->addresses = new Horde_Mail_Rfc822_GroupList(); - } elseif ($addresses instanceof Horde_Mail_Rfc822_GroupList) { - $this->addresses = clone $addresses; - } else { - $rfc822 = new Horde_Mail_Rfc822(); - $this->addresses = $rfc822->parseAddressList($addresses, array( - 'group' => true - )); - } - } - - /** - */ - public function __set($name, $value) - { - switch ($name) { - case 'groupname': - $this->_groupname = Horde_Mime::decode($value); - break; - } - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'groupname': - case 'label': - return $this->_groupname; - - case 'groupname_encoded': - return Horde_Mime::encode($this->_groupname); - - case 'valid': - return (bool)strlen($this->_groupname); - } - } - - /** - */ - protected function _writeAddress($opts) - { - $addr = $this->addresses->writeAddress($opts); - $groupname = $this->groupname; - if (!empty($opts['encode'])) { - $groupname = Horde_Mime::encode($groupname, $opts['encode']); - } - if (empty($opts['noquote'])) { - $rfc822 = new Horde_Mail_Rfc822(); - $groupname = $rfc822->encode($groupname, 'personal'); - } - if (!empty($opts['comment']) && !empty($this->comment)) { - $rfc822 = new Horde_Mail_Rfc822(); - foreach ($this->comment as $val) { - $personal .= ' (' . $rfc822->encode($val, 'comment') . ')'; - } - } - - return ltrim($groupname) . ':' . - (strlen($addr) ? (' ' . $addr) : '') . ';'; - } - - /** - */ - public function match($ob) - { - return $this->addresses->match($ob); - } - - /* Countable methods. */ - - /** - * Address count. - * - * @return integer The number of addresses. - */ - #[\ReturnTypeWillChange] - public function count() - { - return count($this->addresses); - } - -} diff --git a/lib/horde/framework/Horde/Mail/Rfc822/GroupList.php b/lib/horde/framework/Horde/Mail/Rfc822/GroupList.php deleted file mode 100644 index c423801f16a..00000000000 --- a/lib/horde/framework/Horde/Mail/Rfc822/GroupList.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Rfc822_GroupList extends Horde_Mail_Rfc822_List -{ - /** - * Add objects to the container. - * - * @param mixed $obs A RFC 822 object (or list of objects) to store in - * this object. - */ - public function add($obs) - { - if ($obs instanceof Horde_Mail_Rfc822_Object) { - $obs = array($obs); - } - - foreach ($obs as $val) { - /* Only allow addresses. */ - if ($val instanceof Horde_Mail_Rfc822_Address) { - parent::add($val); - } - } - } - - /** - * Group count. - * - * @return integer The number of groups in the list. - */ - public function groupCount() - { - return 0; - } - -} diff --git a/lib/horde/framework/Horde/Mail/Rfc822/Identification.php b/lib/horde/framework/Horde/Mail/Rfc822/Identification.php deleted file mode 100644 index 6596eccacb7..00000000000 --- a/lib/horde/framework/Horde/Mail/Rfc822/Identification.php +++ /dev/null @@ -1,118 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - * @since 2.2.0 - */ -class Horde_Mail_Rfc822_Identification extends Horde_Mail_Rfc822 -{ - /** - * List of message IDs parsed. - * - * @var array - */ - public $ids = array(); - - /** - * Constructor. - * - * @param string $value Identification field value to parse. - */ - public function __construct($value = null) - { - $this->parse($value); - } - - /** - * Parse an identification header. - * - * @param string|null $value Identification field value to parse. - */ - public function parse($value) - { - if (empty($value)) { - return; - } - - $this->_data = $value; - $this->_datalen = strlen($value); - $this->_params['validate'] = true; - $this->_ptr = 0; - - $this->_rfc822SkipLwsp(); - - while ($this->_curr() !== false) { - try { - $this->ids[] = $this->_parseMessageId(); - } catch (Horde_Mail_Exception $e) { - break; - } - - // Some mailers incorrectly insert commas between reference items - if ($this->_curr() == ',') { - $this->_rfc822SkipLwsp(true); - } - } - } - - /** - * Message IDs are defined in RFC 5322 [3.6.4]. In short, they can only - * contain one '@' character. However, Outlook can produce invalid - * Message-IDs containing multiple '@' characters, which will fail the - * strict RFC checks. - * - * Since we don't care about the structure/details of the Message-ID, - * just do a basic parse that considers all characters inside of angled - * brackets to be valid. - * - * @return string A full Message-ID (enclosed in angled brackets). - * - * @throws Horde_Mail_Exception - */ - private function _parseMessageId() - { - $bracket = ($this->_curr(true) === '<'); - $str = '<'; - - while (($chr = $this->_curr(true)) !== false) { - if ($bracket) { - $str .= $chr; - if ($chr == '>') { - $this->_rfc822SkipLwsp(); - return $str; - } - } else { - if (!strcspn($chr, " \n\r\t,")) { - $this->_rfc822SkipLwsp(); - return $str; - } - $str .= $chr; - } - } - - if (!$bracket) { - return $str; - } - - throw new Horde_Mail_Exception('Invalid Message-ID.'); - } - -} diff --git a/lib/horde/framework/Horde/Mail/Rfc822/List.php b/lib/horde/framework/Horde/Mail/Rfc822/List.php deleted file mode 100644 index d098da1583e..00000000000 --- a/lib/horde/framework/Horde/Mail/Rfc822/List.php +++ /dev/null @@ -1,539 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - * - * @property-read array $addresses The list of all addresses (address - * w/personal parts). - * @property-read array $bare_addresses The list of all addresses (mail@host). - * @property-read array $bare_addresses_idn The list of all addresses - * (mail@host; IDN encoded). - * (@since 2.1.0) - * @property-read array $base_addresses The list of ONLY base addresses - * (Address objects). - * @property-read array $raw_addresses The list of all addresses (Address - * objects). - */ -class Horde_Mail_Rfc822_List - extends Horde_Mail_Rfc822_Object - implements ArrayAccess, Countable, SeekableIterator, Serializable -{ - /** Filter masks. */ - const HIDE_GROUPS = 1; - const BASE_ELEMENTS = 2; - - /** - * List data. - * - * @var array - */ - protected $_data = array(); - - /** - * Current Iterator filter. - * - * @var array - */ - protected $_filter = array(); - - /** - * Current Iterator pointer. - * - * @var array - */ - protected $_ptr; - - /** - * Constructor. - * - * @param mixed $obs Address data to store in this object. - */ - public function __construct($obs = null) - { - if (!is_null($obs)) { - $this->add($obs); - } - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'addresses': - case 'bare_addresses': - case 'bare_addresses_idn': - case 'base_addresses': - case 'raw_addresses': - $old = $this->_filter; - $mask = ($name == 'base_addresses') - ? self::BASE_ELEMENTS - : self::HIDE_GROUPS; - $this->setIteratorFilter($mask, empty($old['filter']) ? null : $old['filter']); - - $out = array(); - foreach ($this as $val) { - switch ($name) { - case 'addresses': - $out[] = strval($val); - break; - - case 'bare_addresses': - $out[] = $val->bare_address; - break; - - case 'bare_addresses_idn': - $out[] = $val->bare_address_idn; - break; - - case 'base_addresses': - case 'raw_addresses': - $out[] = clone $val; - break; - } - } - - $this->_filter = $old; - return $out; - } - } - - /** - * Add objects to the container. - * - * @param mixed $obs Address data to store in this object. - */ - public function add($obs) - { - foreach ($this->_normalize($obs) as $val) { - $this->_data[] = $val; - } - } - - /** - * Remove addresses from the container. This method ignores Group objects. - * - * @param mixed $obs Addresses to remove. - */ - public function remove($obs) - { - $old = $this->_filter; - $this->setIteratorFilter(self::HIDE_GROUPS | self::BASE_ELEMENTS); - - foreach ($this->_normalize($obs) as $val) { - $remove = array(); - - foreach ($this as $key => $val2) { - if ($val2->match($val)) { - $remove[] = $key; - } - } - - foreach (array_reverse($remove) as $key) { - unset($this[$key]); - } - } - - $this->_filter = $old; - } - - /** - * Removes duplicate addresses from list. This method ignores Group - * objects. - */ - public function unique() - { - $exist = $remove = array(); - - $old = $this->_filter; - $this->setIteratorFilter(self::HIDE_GROUPS | self::BASE_ELEMENTS); - - // For duplicates, we use the first address that contains personal - // information. - foreach ($this as $key => $val) { - $bare = $val->bare_address; - if (isset($exist[$bare])) { - if (($exist[$bare] == -1) || is_null($val->personal)) { - $remove[] = $key; - } else { - $remove[] = $exist[$bare]; - $exist[$bare] = -1; - } - } else { - $exist[$bare] = is_null($val->personal) - ? $key - : -1; - } - } - - foreach (array_reverse($remove) as $key) { - unset($this[$key]); - } - - $this->_filter = $old; - } - - /** - * Group count. - * - * @return integer The number of groups in the list. - */ - public function groupCount() - { - $ret = 0; - - foreach ($this->_data as $val) { - if ($val instanceof Horde_Mail_Rfc822_Group) { - ++$ret; - } - } - - return $ret; - } - - /** - * Set the Iterator filter. - * - * @param integer $mask Filter masks. - * @param mixed $filter An e-mail, or as list of e-mails, to filter by. - */ - public function setIteratorFilter($mask = 0, $filter = null) - { - $this->_filter = array(); - - if ($mask) { - $this->_filter['mask'] = $mask; - } - - if (!is_null($filter)) { - $rfc822 = new Horde_Mail_Rfc822(); - $this->_filter['filter'] = $rfc822->parseAddressList($filter); - } - } - - /** - */ - protected function _writeAddress($opts) - { - $out = array(); - - foreach ($this->_data as $val) { - $out[] = $val->writeAddress($opts); - } - - return implode(', ', $out); - } - - /** - */ - public function match($ob) - { - if (!($ob instanceof Horde_Mail_Rfc822_List)) { - $ob = new Horde_Mail_Rfc822_List($ob); - } - - $a = $this->bare_addresses; - sort($a); - $b = $ob->bare_addresses; - sort($b); - - return ($a == $b); - } - - /** - * Does this list contain the given e-mail address? - * - * @param mixed $address An e-mail address. - * - * @return boolean True if the e-mail address is contained in the list. - */ - public function contains($address) - { - $ob = new Horde_Mail_Rfc822_Address($address); - - foreach ($this->raw_addresses as $val) { - if ($val->match($ob)) { - return true; - } - } - - return false; - } - - /** - * Convenience method to return the first element in a list. - * - * Useful since it allows chaining; older PHP versions did not allow array - * access dereferencing from the results of a function call. - * - * @since 2.5.0 - * - * @return Horde_Mail_Rfc822_Object Rfc822 object, or null if no object. - */ - public function first() - { - return $this[0]; - } - - /** - * Normalize objects to add to list. - * - * @param mixed $obs Address data to store in this object. - * - * @return array Entries to add. - */ - protected function _normalize($obs) - { - $add = array(); - - if (!($obs instanceof Horde_Mail_Rfc822_List) && - !is_array($obs)) { - $obs = array($obs); - } - - foreach ($obs as $val) { - if (is_string($val)) { - $rfc822 = new Horde_Mail_Rfc822(); - $val = $rfc822->parseAddressList($val); - } - - if ($val instanceof Horde_Mail_Rfc822_List) { - $val->setIteratorFilter(self::BASE_ELEMENTS); - foreach ($val as $val2) { - $add[] = $val2; - } - } elseif ($val instanceof Horde_Mail_Rfc822_Object) { - $add[] = $val; - } - } - - return $add; - } - - /* ArrayAccess methods. */ - - /** - */ - #[\ReturnTypeWillChange] - public function offsetExists($offset) - { - return !is_null($this[$offset]); - } - - /** - */ - #[\ReturnTypeWillChange] - public function offsetGet($offset) - { - try { - $this->seek($offset); - return $this->current(); - } catch (OutOfBoundsException $e) { - return null; - } - } - - /** - */ - #[\ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - if ($ob = $this[$offset]) { - if (is_null($this->_ptr['subidx'])) { - $tmp = $this->_normalize($value); - if (isset($tmp[0])) { - $this->_data[$this->_ptr['idx']] = $tmp[0]; - } - } else { - $ob[$offset] = $value; - } - $this->_ptr = null; - } - } - - /** - */ - #[\ReturnTypeWillChange] - public function offsetUnset($offset) - { - if ($ob = $this[$offset]) { - if (is_null($this->_ptr['subidx'])) { - unset($this->_data[$this->_ptr['idx']]); - $this->_data = array_values($this->_data); - } else { - unset($ob->addresses[$this->_ptr['subidx']]); - } - $this->_ptr = null; - } - } - - /* Countable methods. */ - - /** - * Address count. - * - * @return integer The number of addresses. - */ - #[\ReturnTypeWillChange] - public function count() - { - return count($this->addresses); - } - - /* Iterator methods. */ - - #[\ReturnTypeWillChange] - public function current() - { - if (!$this->valid()) { - return null; - } - - $ob = $this->_data[$this->_ptr['idx']]; - - return is_null($this->_ptr['subidx']) - ? $ob - : $ob->addresses[$this->_ptr['subidx']]; - } - - #[\ReturnTypeWillChange] - public function key() - { - return $this->_ptr['key']; - } - - #[\ReturnTypeWillChange] - public function next() - { - if (is_null($this->_ptr['subidx'])) { - $curr = $this->current(); - if (($curr instanceof Horde_Mail_Rfc822_Group) && count($curr)) { - $this->_ptr['subidx'] = 0; - } else { - ++$this->_ptr['idx']; - } - $curr = $this->current(); - } elseif (!($curr = $this->_data[$this->_ptr['idx']]->addresses[++$this->_ptr['subidx']])) { - $this->_ptr['subidx'] = null; - ++$this->_ptr['idx']; - $curr = $this->current(); - } - - if (!is_null($curr)) { - if (!empty($this->_filter) && $this->_iteratorFilter($curr)) { - $this->next(); - } else { - ++$this->_ptr['key']; - } - } - } - - #[\ReturnTypeWillChange] - public function rewind() - { - $this->_ptr = array( - 'idx' => 0, - 'key' => 0, - 'subidx' => null - ); - - if ($this->valid() && - !empty($this->_filter) && - $this->_iteratorFilter($this->current())) { - $this->next(); - $this->_ptr['key'] = 0; - } - } - - #[\ReturnTypeWillChange] - public function valid() - { - return (!empty($this->_ptr) && isset($this->_data[$this->_ptr['idx']])); - } - - #[\ReturnTypeWillChange] - public function seek($position) - { - if (!$this->valid() || - ($position < $this->_ptr['key'])) { - $this->rewind(); - } - - for ($i = $this->_ptr['key']; ; ++$i) { - if ($i == $position) { - return; - } - - $this->next(); - if (!$this->valid()) { - throw new OutOfBoundsException('Position not found.'); - } - } - } - - protected function _iteratorFilter($ob) - { - if (!empty($this->_filter['mask'])) { - if (($this->_filter['mask'] & self::HIDE_GROUPS) && - ($ob instanceof Horde_Mail_Rfc822_Group)) { - return true; - } - - if (($this->_filter['mask'] & self::BASE_ELEMENTS) && - !is_null($this->_ptr['subidx'])) { - return true; - } - } - - if (!empty($this->_filter['filter']) && - ($ob instanceof Horde_Mail_Rfc822_Address)) { - foreach ($this->_filter['filter'] as $val) { - if ($ob->match($val)) { - return true; - } - } - } - - return false; - } - - /* Serializable methods. */ - - public function serialize() - { - return serialize($this->_data); - } - - public function unserialize($data) - { - $this->_data = unserialize($data); - } - - public function __serialize() { - return array( - 'data' => $this->_data - ); - } - - public function __unserialize(array $data) { - $this->_data = $data['data']; - } - -} diff --git a/lib/horde/framework/Horde/Mail/Rfc822/Object.php b/lib/horde/framework/Horde/Mail/Rfc822/Object.php deleted file mode 100644 index c2d1b246cb7..00000000000 --- a/lib/horde/framework/Horde/Mail/Rfc822/Object.php +++ /dev/null @@ -1,90 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -abstract class Horde_Mail_Rfc822_Object -{ - /** - * String representation of object. - * - * @return string Returns the full e-mail address. - */ - public function __toString() - { - return $this->writeAddress(); - } - - /** - * Write an address given information in this part. - * - * @param mixed $opts If boolean true, is equivalent to passing true for - * both 'encode' and 'idn'. If an array, these - * keys are supported: - * - comment: (boolean) If true, include comment(s) in output? - * @since 2.6.0 - * DEFAULT: false - * - encode: (mixed) MIME encode the personal/groupname parts? - * If boolean true, encodes in 'UTF-8'. - * If a string, encodes using this charset. - * DEFAULT: false - * - idn: (boolean) If true, encodes IDN domain names (RFC 3490). - * DEFAULT: false - * - noquote: (boolean) If true, don't quote personal part. [@since - * 2.4.0] - * DEFAULT: false - * - * @return string The correctly escaped/quoted address. - */ - public function writeAddress($opts = array()) - { - if ($opts === true) { - $opts = array( - 'encode' => 'UTF-8', - 'idn' => true - ); - } elseif (!empty($opts['encode']) && ($opts['encode'] === true)) { - $opts['encode'] = 'UTF-8'; - } - - return $this->_writeAddress($opts); - } - - /** - * Class-specific implementation of writeAddress(). - * - * @see writeAddress() - * - * @param array $opts See writeAddress(). - * - * @return string The correctly escaped/quoted address. - */ - abstract protected function _writeAddress($opts); - - /** - * Compare this object against other data. - * - * @param mixed $ob Address data. - * - * @return boolean True if the data reflects the same canonical address. - */ - abstract public function match($ob); - -} diff --git a/lib/horde/framework/Horde/Mail/Translation.php b/lib/horde/framework/Horde/Mail/Translation.php deleted file mode 100644 index eb5da6c8a79..00000000000 --- a/lib/horde/framework/Horde/Mail/Translation.php +++ /dev/null @@ -1,39 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - * @since 2.5.0 - */ -class Horde_Mail_Translation extends Horde_Translation_Autodetect -{ - /** - * The translation domain - * - * @var string - */ - protected static $_domain = 'Horde_Mail'; - - /** - * The absolute PEAR path to the translations for the default gettext handler. - * - * @var string - */ - protected static $_pearDirectory = '@data_dir@'; -} diff --git a/lib/horde/framework/Horde/Mail/Transport.php b/lib/horde/framework/Horde/Mail/Transport.php deleted file mode 100644 index eea77c8d202..00000000000 --- a/lib/horde/framework/Horde/Mail/Transport.php +++ /dev/null @@ -1,263 +0,0 @@ - - * @author Richard Heyes - * @author Michael Slusarz - * @category Horde - * @copyright 1997-2017 Horde LLC (http://www.horde.org/) - * @copyright 2002-2007 Richard Heyes - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - * - * @property-read boolean $eai Does the transport driver support EAI (RFC - * 6532) headers? (@since 2.5.0) - */ -abstract class Horde_Mail_Transport -{ - /** - * Line terminator used for separating header lines. - * - * @var string - */ - public $sep = PHP_EOL; - - /** - * Configuration parameters. - * - * @var array - */ - protected $_params = array(); - - /** - */ - public function __get($name) - { - switch ($name) { - case 'eai': - return false; - } - } - - /** - * Send a message. - * - * @param mixed $recipients Either a comma-seperated list of recipients - * (RFC822 compliant), or an array of - * recipients, each RFC822 valid. This may - * contain recipients not specified in the - * headers, for Bcc:, resending messages, etc. - * @param array $headers The headers to send with the mail, in an - * associative array, where the array key is the - * header name (ie, 'Subject'), and the array - * value is the header value (ie, 'test'). The - * header produced from those values would be - * 'Subject: test'. - * If the '_raw' key exists, the value of this - * key will be used as the exact text for - * sending the message. - * @param mixed $body The full text of the message body, including - * any Mime parts, etc. Either a string or a - * stream resource. - * - * @throws Horde_Mail_Exception - */ - abstract public function send($recipients, array $headers, $body); - - /** - * Take an array of mail headers and return a string containing text - * usable in sending a message. - * - * @param array $headers The array of headers to prepare, in an - * associative array, where the array key is the - * header name (ie, 'Subject'), and the array value - * is the header value (ie, 'test'). The header - * produced from those values would be 'Subject: - * test'. - * If the '_raw' key exists, the value of this key - * will be used as the exact text for sending the - * message. - * - * @return mixed Returns false if it encounters a bad address; otherwise - * returns an array containing two elements: Any From: - * address found in the headers, and the plain text version - * of the headers. - * @throws Horde_Mail_Exception - */ - public function prepareHeaders(array $headers) - { - $from = null; - $lines = array(); - $raw = isset($headers['_raw']) - ? $headers['_raw'] - : null; - - foreach ($headers as $key => $value) { - if (strcasecmp($key, 'From') === 0) { - $parser = new Horde_Mail_Rfc822(); - $addresses = $parser->parseAddressList($value, array( - 'validate' => $this->eai ? 'eai' : true - )); - $from = $addresses[0]->bare_address; - - // Reject envelope From: addresses with spaces. - if (strstr($from, ' ')) { - return false; - } - - $lines[] = $key . ': ' . $this->_normalizeEOL($value); - } elseif (!$raw && (strcasecmp($key, 'Received') === 0)) { - $received = array(); - if (!is_array($value)) { - $value = array($value); - } - - foreach ($value as $line) { - $received[] = $key . ': ' . $this->_normalizeEOL($line); - } - - // Put Received: headers at the top. Spam detectors often - // flag messages with Received: headers after the Subject: - // as spam. - $lines = array_merge($received, $lines); - } elseif (!$raw) { - // If $value is an array (i.e., a list of addresses), convert - // it to a comma-delimited string of its elements (addresses). - if (is_array($value)) { - $value = implode(', ', $value); - } - $lines[] = $key . ': ' . $this->_normalizeEOL($value); - } - } - - return array($from, $raw ? $raw : implode($this->sep, $lines)); - } - - /** - * Take a set of recipients and parse them, returning an array of bare - * addresses (forward paths) that can be passed to sendmail or an SMTP - * server with the 'RCPT TO:' command. - * - * @param mixed $recipients Either a comma-separated list of recipients - * (RFC822 compliant), or an array of - * recipients, each RFC822 valid. - * - * @return array Forward paths (bare addresses, IDN encoded). - * @throws Horde_Mail_Exception - */ - public function parseRecipients($recipients) - { - // Parse recipients, leaving out all personal info. This is - // for smtp recipients, etc. All relevant personal information - // should already be in the headers. - $rfc822 = new Horde_Mail_Rfc822(); - return $rfc822->parseAddressList($recipients, array( - 'validate' => $this->eai ? 'eai' : true - ))->bare_addresses_idn; - } - - /** - * Sanitize an array of mail headers by removing any additional header - * strings present in a legitimate header's value. The goal of this - * filter is to prevent mail injection attacks. - * - * Raw headers are sent as-is. - * - * @param array $headers The associative array of headers to sanitize. - * - * @return array The sanitized headers. - */ - protected function _sanitizeHeaders($headers) - { - foreach (array_diff(array_keys($headers), array('_raw')) as $key) { - $headers[$key] = preg_replace('=((||0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i', '', $headers[$key]); - } - - return $headers; - } - - /** - * Normalizes EOLs in string data. - * - * @param string $data Data. - * - * @return string Normalized data. - */ - protected function _normalizeEOL($data) - { - return strtr($data, array( - "\r\n" => $this->sep, - "\r" => $this->sep, - "\n" => $this->sep - )); - } - - /** - * Get the from address. - * - * @param string $from From address. - * @param array $headers Headers array. - * - * @return string Address object. - * @throws Horde_Mail_Exception - */ - protected function _getFrom($from, $headers) - { - /* Since few MTAs are going to allow this header to be forged unless - * it's in the MAIL FROM: exchange, we'll use Return-Path instead of - * From: if it's set. */ - foreach (array_keys($headers) as $hdr) { - if (strcasecmp($hdr, 'Return-Path') === 0) { - $from = $headers[$hdr]; - break; - } - } - - if (empty($from)) { - throw new Horde_Mail_Exception('No from address provided.'); - } - - $from = new Horde_Mail_Rfc822_Address($from); - - return $from->bare_address_idn; - } - -} diff --git a/lib/horde/framework/Horde/Mail/Transport/Lmtphorde.php b/lib/horde/framework/Horde/Mail/Transport/Lmtphorde.php deleted file mode 100644 index 471fae2cdc9..00000000000 --- a/lib/horde/framework/Horde/Mail/Transport/Lmtphorde.php +++ /dev/null @@ -1,64 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Transport_Lmtphorde extends Horde_Mail_Transport_Smtphorde -{ - /** - */ - public function getSMTPObject() - { - if (!$this->_smtp) { - $this->_smtp = new Horde_Smtp_Lmtp($this->_params); - try { - $this->_smtp->login(); - } catch (Horde_Smtp_Exception $e) { - throw new Horde_Mail_Exception($e); - } - } - - return $this->_smtp; - } - -} diff --git a/lib/horde/framework/Horde/Mail/Transport/Mail.php b/lib/horde/framework/Horde/Mail/Transport/Mail.php deleted file mode 100644 index a9b3067f775..00000000000 --- a/lib/horde/framework/Horde/Mail/Transport/Mail.php +++ /dev/null @@ -1,115 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @copyright 2010-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Transport_Mail extends Horde_Mail_Transport -{ - /** - * @param array $params Additional parameters: - * - args: (string) Extra arguments for the mail() function. - */ - public function __construct(array $params = array()) - { - $this->_params = array_merge($this->_params, $params); - } - - /** - */ - public function send($recipients, array $headers, $body) - { - $headers = $this->_sanitizeHeaders($headers); - $recipients = implode(',', $this->parseRecipients($recipients)); - $subject = ''; - - foreach (array_keys($headers) as $hdr) { - if (strcasecmp($hdr, 'Subject') === 0) { - // Get the Subject out of the headers array so that we can - // pass it as a separate argument to mail(). - $subject = $headers[$hdr]; - unset($headers[$hdr]); - } elseif (strcasecmp($hdr, 'To') === 0) { - // Remove the To: header. The mail() function will add its - // own To: header based on the contents of $recipients. - unset($headers[$hdr]); - } - } - - // Flatten the headers out. - list(, $text_headers) = $this->prepareHeaders($headers); - - // mail() requires a string for $body. If resource, need to convert - // to a string. - if (is_resource($body)) { - $body_str = ''; - - stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol'); - stream_filter_append($body, 'horde_eol', STREAM_FILTER_READ, array('eol' => $this->sep)); - - rewind($body); - while (!feof($body)) { - $body_str .= fread($body, 8192); - } - $body = $body_str; - } else { - // Convert EOL characters in body. - $body = $this->_normalizeEOL($body); - } - - // We only use mail()'s optional fifth parameter if the additional - // parameters have been provided and we're not running in safe mode. - if (empty($this->_params) || ini_get('safe_mode')) { - $result = mail($recipients, $subject, $body, $text_headers); - } else { - $result = mail($recipients, $subject, $body, $text_headers, isset($this->_params['args']) ? $this->_params['args'] : ''); - } - - // If the mail() function returned failure, we need to create an - // Exception and return it instead of the boolean result. - if ($result === false) { - throw new Horde_Mail_Exception('mail() returned failure.'); - } - } - -} diff --git a/lib/horde/framework/Horde/Mail/Transport/Mock.php b/lib/horde/framework/Horde/Mail/Transport/Mock.php deleted file mode 100644 index e791e534f59..00000000000 --- a/lib/horde/framework/Horde/Mail/Transport/Mock.php +++ /dev/null @@ -1,126 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @copyright 2010-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Transport_Mock extends Horde_Mail_Transport -{ - /** - * Array of messages that have been sent with the mock. - * - * @var array - */ - public $sentMessages = array(); - - /** - * Callback before sending mail. - * - * @var callback - */ - protected $_preSendCallback; - - /** - * Callback after sending mai. - * - * @var callback - */ - protected $_postSendCallback; - - /** - * @param array Optional parameters: - * - postSendCallback: (callback) Called after an email would have been - * sent. - * - preSendCallback: (callback) Called before an email would be sent. - */ - public function __construct(array $params = array()) - { - if (isset($params['preSendCallback']) && - is_callable($params['preSendCallback'])) { - $this->_preSendCallback = $params['preSendCallback']; - } - - if (isset($params['postSendCallback']) && - is_callable($params['postSendCallback'])) { - $this->_postSendCallback = $params['postSendCallback']; - } - } - - /** - */ - public function send($recipients, array $headers, $body) - { - if ($this->_preSendCallback) { - call_user_func_array($this->_preSendCallback, array($this, $recipients, $headers, $body)); - } - - $headers = $this->_sanitizeHeaders($headers); - list($from, $text_headers) = $this->prepareHeaders($headers); - - if (is_resource($body)) { - stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol'); - stream_filter_append($body, 'horde_eol', STREAM_FILTER_READ, array('eol' => $this->sep)); - - rewind($body); - $body_txt = stream_get_contents($body); - } else { - $body_txt = $this->_normalizeEOL($body); - } - - $from = $this->_getFrom($from, $headers); - $recipients = $this->parseRecipients($recipients); - - $this->sentMessages[] = array( - 'body' => $body_txt, - 'from' => $from, - 'headers' => $headers, - 'header_text' => $text_headers, - 'recipients' => $recipients - ); - - if ($this->_postSendCallback) { - call_user_func_array($this->_postSendCallback, array($this, $recipients, $headers, $body_txt)); - } - } - -} diff --git a/lib/horde/framework/Horde/Mail/Transport/Null.php b/lib/horde/framework/Horde/Mail/Transport/Null.php deleted file mode 100644 index 8c5264f99c7..00000000000 --- a/lib/horde/framework/Horde/Mail/Transport/Null.php +++ /dev/null @@ -1,58 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @copyright 2010-2017 Horde LLC - * @copyright 2010 Phil Kernick - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Transport_Null extends Horde_Mail_Transport -{ - /** - */ - public function send($recipients, array $headers, $body) - { - } - -} diff --git a/lib/horde/framework/Horde/Mail/Transport/Sendmail.php b/lib/horde/framework/Horde/Mail/Transport/Sendmail.php deleted file mode 100644 index 4f36e58daf5..00000000000 --- a/lib/horde/framework/Horde/Mail/Transport/Sendmail.php +++ /dev/null @@ -1,195 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @copyright 2010-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Transport_Sendmail extends Horde_Mail_Transport -{ - /** - * Any extra command-line parameters to pass to the sendmail or - * sendmail wrapper binary. - * - * @var string - */ - protected $_sendmailArgs = '-i'; - - /** - * The location of the sendmail or sendmail wrapper binary on the - * filesystem. - * - * @var string - */ - protected $_sendmailPath = '/usr/sbin/sendmail'; - - /** - * Constructor. - * - * @param array $params Additional parameters: - * - sendmail_args: (string) Any extra parameters to pass to the sendmail - * or sendmail wrapper binary. - * DEFAULT: -i - * - sendmail_path: (string) The location of the sendmail binary on the - * filesystem. - * DEFAULT: /usr/sbin/sendmail - */ - public function __construct(array $params = array()) - { - if (isset($params['sendmail_args'])) { - $this->_sendmailArgs = $params['sendmail_args']; - } - - if (isset($params['sendmail_path'])) { - $this->_sendmailPath = $params['sendmail_path']; - } - } - - /** - */ - public function send($recipients, array $headers, $body) - { - $recipients = implode(' ', array_map('escapeshellarg', $this->parseRecipients($recipients))); - - $headers = $this->_sanitizeHeaders($headers); - list($from, $text_headers) = $this->prepareHeaders($headers); - $from = $this->_getFrom($from, $headers); - - $mail = @popen($this->_sendmailPath . (empty($this->_sendmailArgs) ? '' : ' ' . $this->_sendmailArgs) . ' -f ' . escapeshellarg($from) . ' -- ' . $recipients, 'w'); - if (!$mail) { - throw new Horde_Mail_Exception('Failed to open sendmail [' . $this->_sendmailPath . '] for execution.'); - } - - // Write the headers following by two newlines: one to end the headers - // section and a second to separate the headers block from the body. - fputs($mail, $text_headers . $this->sep . $this->sep); - - if (is_resource($body)) { - stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol'); - stream_filter_append($body, 'horde_eol', STREAM_FILTER_READ, array('eol' => $this->sep)); - - rewind($body); - while (!feof($body)) { - fputs($mail, fread($body, 8192)); - } - } else { - fputs($mail, $this->_normalizeEOL($body)); - } - $result = pclose($mail); - - if (!$result) { - return; - } - - switch ($result) { - case 64: // EX_USAGE - $msg = 'command line usage error'; - break; - - case 65: // EX_DATAERR - $msg = 'data format error'; - break; - - case 66: // EX_NOINPUT - $msg = 'cannot open input'; - break; - - case 67: // EX_NOUSER - $msg = 'addressee unknown'; - break; - - case 68: // EX_NOHOST - $msg = 'host name unknown'; - break; - - case 69: // EX_UNAVAILABLE - $msg = 'service unavailable'; - break; - - case 70: // EX_SOFTWARE - $msg = 'internal software error'; - break; - - case 71: // EX_OSERR - $msg = 'system error'; - break; - - case 72: // EX_OSFILE - $msg = 'critical system file missing'; - break; - - case 73: // EX_CANTCREAT - $msg = 'cannot create output file'; - break; - - case 74: // EX_IOERR - $msg = 'input/output error'; - - case 75: // EX_TEMPFAIL - $msg = 'temporary failure'; - break; - - case 76: // EX_PROTOCOL - $msg = 'remote error in protocol'; - break; - - case 77: // EX_NOPERM - $msg = 'permission denied'; - break; - - case 78: // EX_CONFIG - $msg = 'configuration error'; - break; - - case 79: // EX_NOTFOUND - $msg = 'entry not found'; - break; - - default: - $msg = 'unknown error'; - break; - } - - throw new Horde_Mail_Exception('sendmail: ' . $msg . ' (' . $result . ')', $result); - } - -} diff --git a/lib/horde/framework/Horde/Mail/Transport/Smtp.php b/lib/horde/framework/Horde/Mail/Transport/Smtp.php deleted file mode 100644 index e6d49d71d39..00000000000 --- a/lib/horde/framework/Horde/Mail/Transport/Smtp.php +++ /dev/null @@ -1,350 +0,0 @@ - - * @author Jon Parise - * @author Michael Slusarz - * @category Horde - * @copyright 2010-2016 Horde LLC - * @deprecated Use Horde_Mail_Transport_Hordesmtp instead - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Transport_Smtp extends Horde_Mail_Transport -{ - /* Error: Failed to create a Net_SMTP object */ - const ERROR_CREATE = 10000; - - /* Error: Failed to connect to SMTP server */ - const ERROR_CONNECT = 10001; - - /* Error: SMTP authentication failure */ - const ERROR_AUTH = 10002; - - /* Error: No From: address has been provided */ - const ERROR_FROM = 10003; - - /* Error: Failed to set sender */ - const ERROR_SENDER = 10004; - - /* Error: Failed to add recipient */ - const ERROR_RECIPIENT = 10005; - - /* Error: Failed to send data */ - const ERROR_DATA = 10006; - - /** - * The SMTP greeting. - * - * @var string - */ - public $greeting = null; - - /** - * The SMTP queued response. - * - * @var string - */ - public $queuedAs = null; - - /** - * SMTP connection object. - * - * @var Net_SMTP - */ - protected $_smtp = null; - - /** - * The list of service extension parameters to pass to the Net_SMTP - * mailFrom() command. - * - * @var array - */ - protected $_extparams = array(); - - /** - * Constructor. - * - * @param array $params Additional parameters: - * - auth: (mixed) SMTP authentication. - * This value may be set to true, false or the name of a - * specific authentication method. If the value is set to true, - * the Net_SMTP package will attempt to use the best - * authentication method advertised by the remote SMTP server. - * DEFAULT: false. - * - debug: (boolean) Activate SMTP debug mode? - * DEFAULT: false - * - host: (string) The server to connect to. - * DEFAULT: localhost - * - localhost: (string) Hostname or domain that will be sent to the - * remote SMTP server in the HELO / EHLO message. - * DEFAULT: localhost - * - password: (string) The password to use for SMTP auth. - * DEFAULT: NONE - * - persist: (boolean) Should the SMTP connection persist? - * DEFAULT: false - * - pipelining: (boolean) Use SMTP command pipelining. - * Use SMTP command pipelining (specified in RFC 2920) if - * the SMTP server supports it. This speeds up delivery - * over high-latency connections. - * DEFAULT: false (use default value from Net_SMTP) - * - port: (integer) The port to connect to. - * DEFAULT: 25 - * - timeout: (integer) The SMTP connection timeout. - * DEFAULT: NONE - * - username: (string) The username to use for SMTP auth. - * DEFAULT: NONE - */ - public function __construct(array $params = array()) - { - $this->_params = array_merge(array( - 'auth' => false, - 'debug' => false, - 'host' => 'localhost', - 'localhost' => 'localhost', - 'password' => '', - 'persist' => false, - 'pipelining' => false, - 'port' => 25, - 'timeout' => null, - 'username' => '' - ), $params); - - /* Destructor implementation to ensure that we disconnect from any - * potentially-alive persistent SMTP connections. */ - register_shutdown_function(array($this, 'disconnect')); - - /* SMTP requires CRLF line endings. */ - $this->sep = "\r\n"; - } - - /** - */ - public function send($recipients, array $headers, $body) - { - /* If we don't already have an SMTP object, create one. */ - $this->getSMTPObject(); - - $headers = $this->_sanitizeHeaders($headers); - - /* Make sure the message has a trailing newline. */ - if (is_resource($body)) { - fseek($body, -1, SEEK_END); - switch (fgetc($body)) { - case "\r": - if (fgetc($body) != "\n") { - fputs($body, "\n"); - } - break; - - default: - fputs($body, "\r\n"); - break; - } - rewind($body); - } elseif (substr($body, -2, 0) != "\r\n") { - $body .= "\r\n"; - } - - try { - list($from, $textHeaders) = $this->prepareHeaders($headers); - } catch (Horde_Mail_Exception $e) { - $this->_smtp->rset(); - throw $e; - } - - try { - $from = $this->_getFrom($from, $headers); - } catch (Horde_Mail_Exception $e) { - $this->_smtp->rset(); - throw new Horde_Mail_Exception('No From: address has been provided', self::ERROR_FROM); - } - - $params = ''; - foreach ($this->_extparams as $key => $val) { - $params .= ' ' . $key . (is_null($val) ? '' : '=' . $val); - } - - $res = $this->_smtp->mailFrom($from, ltrim($params)); - if ($res instanceof PEAR_Error) { - $this->_error(sprintf("Failed to set sender: %s", $from), $res, self::ERROR_SENDER); - } - - try { - $recipients = $this->parseRecipients($recipients); - } catch (Horde_Mail_Exception $e) { - $this->_smtp->rset(); - throw $e; - } - - foreach ($recipients as $recipient) { - $res = $this->_smtp->rcptTo($recipient); - if ($res instanceof PEAR_Error) { - $this->_error("Failed to add recipient: $recipient", $res, self::ERROR_RECIPIENT); - } - } - - /* Send the message's headers and the body as SMTP data. Net_SMTP does - * the necessary EOL conversions. */ - $res = $this->_smtp->data($body, $textHeaders); - list(,$args) = $this->_smtp->getResponse(); - - if (preg_match("/Ok: queued as (.*)/", $args, $queued)) { - $this->queuedAs = $queued[1]; - } - - /* We need the greeting; from it we can extract the authorative name - * of the mail server we've really connected to. Ideal if we're - * connecting to a round-robin of relay servers and need to track - * which exact one took the email */ - $this->greeting = $this->_smtp->getGreeting(); - - if ($res instanceof PEAR_Error) { - $this->_error('Failed to send data', $res, self::ERROR_DATA); - } - - /* If persistent connections are disabled, destroy our SMTP object. */ - if (!$this->_params['persist']) { - $this->disconnect(); - } - } - - /** - * Connect to the SMTP server by instantiating a Net_SMTP object. - * - * @return Net_SMTP The SMTP object. - * @throws Horde_Mail_Exception - */ - public function getSMTPObject() - { - if ($this->_smtp) { - return $this->_smtp; - } - - $this->_smtp = new Net_SMTP( - $this->_params['host'], - $this->_params['port'], - $this->_params['localhost'] - ); - - /* Set pipelining. */ - if ($this->_params['pipelining']) { - $this->_smtp->pipelining = true; - } - - /* If we still don't have an SMTP object at this point, fail. */ - if (!($this->_smtp instanceof Net_SMTP)) { - throw new Horde_Mail_Exception('Failed to create a Net_SMTP object', self::ERROR_CREATE); - } - - /* Configure the SMTP connection. */ - if ($this->_params['debug']) { - $this->_smtp->setDebug(true); - } - - /* Attempt to connect to the configured SMTP server. */ - $res = $this->_smtp->connect($this->_params['timeout']); - if ($res instanceof PEAR_Error) { - $this->_error('Failed to connect to ' . $this->_params['host'] . ':' . $this->_params['port'], $res, self::ERROR_CONNECT); - } - - /* Attempt to authenticate if authentication has been enabled. */ - if ($this->_params['auth']) { - $method = is_string($this->_params['auth']) - ? $this->_params['auth'] - : ''; - - $res = $this->_smtp->auth($this->_params['username'], $this->_params['password'], $method); - if ($res instanceof PEAR_Error) { - $this->_error("$method authentication failure", $res, self::ERROR_AUTH); - } - } - - return $this->_smtp; - } - - /** - * Add parameter associated with a SMTP service extension. - * - * @param string $keyword Extension keyword. - * @param string $value Any value the keyword needs. - */ - public function addServiceExtensionParameter($keyword, $value = null) - { - $this->_extparams[$keyword] = $value; - } - - /** - * Disconnect and destroy the current SMTP connection. - * - * @return boolean True if the SMTP connection no longer exists. - */ - public function disconnect() - { - /* If we have an SMTP object, disconnect and destroy it. */ - if (is_object($this->_smtp) && $this->_smtp->disconnect()) { - $this->_smtp = null; - } - - /* We are disconnected if we no longer have an SMTP object. */ - return ($this->_smtp === null); - } - - /** - * Build a standardized string describing the current SMTP error. - * - * @param string $text Custom string describing the error context. - * @param PEAR_Error $error PEAR_Error object. - * @param integer $e_code Error code. - * - * @throws Horde_Mail_Exception - */ - protected function _error($text, $error, $e_code) - { - /* Split the SMTP response into a code and a response string. */ - list($code, $response) = $this->_smtp->getResponse(); - - /* Abort current SMTP transaction. */ - $this->_smtp->rset(); - - /* Build our standardized error string. */ - throw new Horde_Mail_Exception($text . ' [SMTP: ' . $error->getMessage() . " (code: $code, response: $response)]", $e_code); - } - -} diff --git a/lib/horde/framework/Horde/Mail/Transport/Smtphorde.php b/lib/horde/framework/Horde/Mail/Transport/Smtphorde.php deleted file mode 100644 index ee9037ca6fe..00000000000 --- a/lib/horde/framework/Horde/Mail/Transport/Smtphorde.php +++ /dev/null @@ -1,169 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Transport_Smtphorde extends Horde_Mail_Transport -{ - /** - * @deprecated - */ - public $send8bit = false; - - /** - * SMTP object. - * - * @var Horde_Smtp - */ - protected $_smtp = null; - - /** - * Constructor. - * - * @param array $params Additional parameters: - * - chunk_size: (integer) If CHUNKING is supported on the server, the - * chunk size (in octets) to send. 0 will disable chunking. - * @since Horde_Smtp 1.7.0 - * - context: (array) Any context parameters passed to - * stream_create_context(). @since Horde_Smtp 1.9.0 - * - debug: (string) If set, will output debug information to the stream - * provided. The value can be any PHP supported wrapper that - * can be opened via fopen(). - * DEFAULT: No debug output - * - host: (string) The SMTP server. - * DEFAULT: localhost - * - localhost: (string) The hostname of the localhost. (since Horde_Smtp - 1.9.0) - * DEFAULT: Auto-determined. - * - password: (string) The SMTP password. - * DEFAULT: NONE - * - port: (string) The SMTP port. - * DEFAULT: 587 - * - secure: (string) Use SSL or TLS to connect. - * DEFAULT: true (use 'tls' option, if available) - * - false (No encryption) - * - 'ssl' (Auto-detect SSL version) - * - 'sslv2' (Force SSL version 2) - * - 'sslv3' (Force SSL version 3) - * - 'tls' (TLS; started via protocol-level negotation over - * unencrypted channel; RECOMMENDED way of initiating secure - * connection) - * - 'tlsv1' (TLS direct version 1.x connection to server) [@since - * Horde_Smtp .3.0] - * - true (Use TLS, if available) [@since Horde_Smtp 1.2.0] - * DEFAULT: No encryption - * - timeout: (integer) Connection timeout, in seconds. - * DEFAULT: 30 seconds - * - username: (string) The SMTP username. - * DEFAULT: NONE - * - xoauth2_token: (string) If set, will authenticate via the XOAUTH2 - * mechanism (if available) with this token. Either a - * string or a Horde_Smtp_Password object (since - * Horde_Smtp 1.1.0). - */ - public function __construct(array $params = array()) - { - $this->_params = $params; - - /* SMTP requires CRLF line endings. */ - $this->sep = "\r\n"; - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'eai': - $this->getSMTPObject(); - return $this->_smtp->data_intl; - } - - return parent::__get($name); - } - - /** - */ - public function send($recipients, array $headers, $body) - { - /* If we don't already have an SMTP object, create one. */ - $this->getSMTPObject(); - - $headers = $this->_sanitizeHeaders($headers); - list($from, $textHeaders) = $this->prepareHeaders($headers); - $from = $this->_getFrom($from, $headers); - - $combine = Horde_Stream_Wrapper_Combine::getStream(array( - rtrim($textHeaders, $this->sep), - $this->sep . $this->sep, - $body - )); - - try { - $this->_smtp->send($from, $recipients, $combine); - } catch (Horde_Smtp_Exception $e) { - throw new Horde_Mail_Exception($e); - } - } - - /** - * Connect to the SMTP server by instantiating a Horde_Smtp object. - * - * @return Horde_Smtp The SMTP object. - * @throws Horde_Mail_Exception - */ - public function getSMTPObject() - { - if (!$this->_smtp) { - $this->_smtp = new Horde_Smtp($this->_params); - try { - $this->_smtp->login(); - } catch (Horde_Smtp_Exception $e) { - throw new Horde_Mail_Exception($e); - } - } - - return $this->_smtp; - } - -} diff --git a/lib/horde/framework/Horde/Mail/Transport/Smtpmx.php b/lib/horde/framework/Horde/Mail/Transport/Smtpmx.php deleted file mode 100644 index 69126835cec..00000000000 --- a/lib/horde/framework/Horde/Mail/Transport/Smtpmx.php +++ /dev/null @@ -1,362 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @copyright 2010-2016 Horde LLC - * @copyright 2010 Gerd Schaufelberger - * @deprecated Use Horde_Mail_Transport_Hordesmtp instead - * @license http://www.horde.org/licenses/bsd New BSD License - * @package Mail - */ -class Horde_Mail_Transport_Smtpmx extends Horde_Mail_Transport -{ - /** - * SMTP connection object. - * - * @var Net_SMTP - */ - protected $_smtp = null; - - /** - * Net_DNS2_Resolver object. - * - * @var Net_DNS2_Resolver - */ - protected $_resolver; - - /** - * Internal error codes. - * Translate internal error identifier to human readable messages. - * - * @var array - */ - protected $_errorCode = array( - 'not_connected' => array( - 'code' => 1, - 'msg' => 'Could not connect to any mail server ({HOST}) at port {PORT} to send mail to {RCPT}.' - ), - 'failed_vrfy_rcpt' => array( - 'code' => 2, - 'msg' => 'Recipient "{RCPT}" could not be veryfied.' - ), - 'failed_set_from' => array( - 'code' => 3, - 'msg' => 'Failed to set sender: {FROM}.' - ), - 'failed_set_rcpt' => array( - 'code' => 4, - 'msg' => 'Failed to set recipient: {RCPT}.' - ), - 'failed_send_data' => array( - 'code' => 5, - 'msg' => 'Failed to send mail to: {RCPT}.' - ), - 'no_from' => array( - 'code' => 5, - 'msg' => 'No from address has be provided.' - ), - 'send_data' => array( - 'code' => 7, - 'msg' => 'Failed to create Net_SMTP object.' - ), - 'no_mx' => array( - 'code' => 8, - 'msg' => 'No MX-record for {RCPT} found.' - ), - 'no_resolver' => array( - 'code' => 9, - 'msg' => 'Could not start resolver! Install PEAR:Net_DNS2 or switch off "netdns"' - ), - 'failed_rset' => array( - 'code' => 10, - 'msg' => 'RSET command failed, SMTP-connection corrupt.' - ) - ); - - /** - * @param array $params Additional options: - * - debug: (boolean) Activate SMTP debug mode? - * DEFAULT: false - * - mailname: (string) The name of the local mail system (a valid - * hostname which matches the reverse lookup) - * DEFAULT: Auto-determined - * - netdns: (boolean) Use PEAR:Net_DNS2 (true) or the PHP builtin - * getmxrr(). - * DEFAULT: true - * - port: (integer) Port. - * DEFAULT: Auto-determined - * - test: (boolean) Activate test mode? - * DEFAULT: false - * - timeout: (integer) The SMTP connection timeout (in seconds). - * DEFAULT: 10 - * - verp: (boolean) Whether to use VERP. - * If not a boolean, the string value will be used as the VERP - * separators. - * DEFAULT: false - * - vrfy: (boolean) Whether to use VRFY. - * DEFAULT: false - */ - public function __construct(array $params = array()) - { - /* Try to find a valid mailname. */ - if (!isset($params['mailname']) && function_exists('posix_uname')) { - $uname = posix_uname(); - $params['mailname'] = $uname['nodename']; - } - - if (!isset($params['port'])) { - $params['port'] = getservbyname('smtp', 'tcp'); - } - - $this->_params = array_merge(array( - 'debug' => false, - 'mailname' => 'localhost', - 'netdns' => true, - 'port' => 25, - 'test' => false, - 'timeout' => 10, - 'verp' => false, - 'vrfy' => false - ), $params); - - /* SMTP requires CRLF line endings. */ - $this->sep = "\r\n"; - } - - /** - * Destructor implementation to ensure that we disconnect from any - * potentially-alive persistent SMTP connections. - */ - public function __destruct() - { - if (is_object($this->_smtp)) { - $this->_smtp->disconnect(); - $this->_smtp = null; - } - } - - /** - */ - public function send($recipients, array $headers, $body) - { - $headers = $this->_sanitizeHeaders($headers); - - // Prepare headers - list($from, $textHeaders) = $this->prepareHeaders($headers); - - try { - $from = $this->_getFrom($from, $headers); - } catch (Horde_Mail_Exception $e) { - $this->_error('no_from'); - } - - // Prepare recipients - foreach ($this->parseRecipients($recipients) as $rcpt) { - list(,$host) = explode('@', $rcpt); - - $mx = $this->_getMx($host); - if (!$mx) { - $this->_error('no_mx', array('rcpt' => $rcpt)); - } - - $connected = false; - foreach (array_keys($mx) as $mserver) { - $this->_smtp = new Net_SMTP($mserver, $this->_params['port'], $this->_params['mailname']); - - // configure the SMTP connection. - if ($this->_params['debug']) { - $this->_smtp->setDebug(true); - } - - // attempt to connect to the configured SMTP server. - $res = $this->_smtp->connect($this->_params['timeout']); - if ($res instanceof PEAR_Error) { - $this->_smtp = null; - continue; - } - - // connection established - if ($res) { - $connected = true; - break; - } - } - - if (!$connected) { - $this->_error('not_connected', array( - 'host' => implode(', ', array_keys($mx)), - 'port' => $this->_params['port'], - 'rcpt' => $rcpt - )); - } - - // Verify recipient - if ($this->_params['vrfy']) { - $res = $this->_smtp->vrfy($rcpt); - if ($res instanceof PEAR_Error) { - $this->_error('failed_vrfy_rcpt', array('rcpt' => $rcpt)); - } - } - - // mail from: - $args['verp'] = $this->_params['verp']; - $res = $this->_smtp->mailFrom($from, $args); - if ($res instanceof PEAR_Error) { - $this->_error('failed_set_from', array('from' => $from)); - } - - // rcpt to: - $res = $this->_smtp->rcptTo($rcpt); - if ($res instanceof PEAR_Error) { - $this->_error('failed_set_rcpt', array('rcpt' => $rcpt)); - } - - // Don't send anything in test mode - if ($this->_params['test']) { - $res = $this->_smtp->rset(); - if ($res instanceof PEAR_Error) { - $this->_error('failed_rset'); - } - - $this->_smtp->disconnect(); - $this->_smtp = null; - return; - } - - // Send data. Net_SMTP does necessary EOL conversions. - $res = $this->_smtp->data($body, $textHeaders); - if ($res instanceof PEAR_Error) { - $this->_error('failed_send_data', array('rcpt' => $rcpt)); - } - - $this->_smtp->disconnect(); - $this->_smtp = null; - } - } - - /** - * Recieve MX records for a host. - * - * @param string $host Mail host. - * - * @return mixed Sorted MX list or false on error. - */ - protected function _getMx($host) - { - $mx = array(); - - if ($this->params['netdns']) { - $this->_loadNetDns(); - - try { - $response = $this->_resolver->query($host, 'MX'); - if (!$response) { - return false; - } - } catch (Exception $e) { - throw new Horde_Mail_Exception($e); - } - - foreach ($response->answer as $rr) { - if ($rr->type == 'MX') { - $mx[$rr->exchange] = $rr->preference; - } - } - } else { - $mxHost = $mxWeight = array(); - - if (!getmxrr($host, $mxHost, $mxWeight)) { - return false; - } - - for ($i = 0; $i < count($mxHost); ++$i) { - $mx[$mxHost[$i]] = $mxWeight[$i]; - } - } - - asort($mx); - - return $mx; - } - - /** - * Initialize Net_DNS2_Resolver. - */ - protected function _loadNetDns() - { - if (!$this->_resolver) { - if (!class_exists('Net_DNS2_Resolver')) { - $this->_error('no_resolver'); - } - $this->_resolver = new Net_DNS2_Resolver(); - } - } - - /** - * Format error message. - * - * @param string $id Maps error ids to codes and message. - * @param array $info Optional information in associative array. - * - * @throws Horde_Mail_Exception - */ - protected function _error($id, $info = array()) - { - $msg = $this->_errorCode[$id]['msg']; - - // include info to messages - if (!empty($info)) { - $replace = $search = array(); - - foreach ($info as $key => $value) { - $search[] = '{' . Horde_String::upper($key) . '}'; - $replace[] = $value; - } - - $msg = str_replace($search, $replace, $msg); - } - - throw new Horde_Mail_Exception($msg, $this->_errorCode[$id]['code']); - } - -} diff --git a/lib/horde/framework/Horde/Mime.php b/lib/horde/framework/Horde/Mime.php deleted file mode 100644 index b61f12d8463..00000000000 --- a/lib/horde/framework/Horde/Mime.php +++ /dev/null @@ -1,397 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @copyright 1999-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ -class Horde_Mime -{ - /** - * The RFC defined EOL string. - * - * @var string - */ - const EOL = "\r\n"; - - /** - * Use windows-1252 charset when decoding ISO-8859-1 data? - * HTML 5 requires this behavior, so it is the default. - * - * @var boolean - */ - public static $decodeWindows1252 = true; - - /** - * Determines if a string contains 8-bit (non US-ASCII) characters. - * - * @param string $string The string to check. - * @param string $charset The charset of the string. Defaults to - * US-ASCII. (@deprecated) - * - * @return boolean True if string contains non 7-bit characters. - */ - public static function is8bit($string, $charset = null) - { - $string = strval($string); - for ($i = 0, $len = strlen($string); $i < $len; ++$i) { - if (ord($string[$i]) > 127) { - return true; - } - } - - return false; - } - - /** - * MIME encodes a string (RFC 2047). - * - * @param string $text The text to encode (UTF-8). - * @param string $charset The character set to encode to. - * - * @return string The MIME encoded string (US-ASCII). - */ - public static function encode($text, $charset = 'UTF-8') - { - $charset = Horde_String::lower($charset); - $text = Horde_String::convertCharset($text, 'UTF-8', $charset); - - $encoded = $is_encoded = false; - $lwsp = $word = null; - $out = ''; - - /* 0 = word unencoded - * 1 = word encoded - * 2 = spaces */ - $parts = array(); - - /* Tokenize string. */ - for ($i = 0, $len = strlen($text); $i < $len; ++$i) { - switch ($text[$i]) { - case "\t": - case "\r": - case "\n": - if (!is_null($word)) { - $parts[] = array(intval($encoded), $word, $i - $word); - $word = null; - } elseif (!is_null($lwsp)) { - $parts[] = array(2, $lwsp, $i - $lwsp); - $lwsp = null; - } - - $parts[] = array(0, $i, 1); - break; - - case ' ': - if (!is_null($word)) { - $parts[] = array(intval($encoded), $word, $i - $word); - $word = null; - } - if (is_null($lwsp)) { - $lwsp = $i; - } - break; - - default: - if (is_null($word)) { - $encoded = false; - $word = $i; - if (!is_null($lwsp)) { - $parts[] = array(2, $lwsp, $i - $lwsp); - $lwsp = null; - } - - /* Check for MIME encoding delimiter. Encode it if - * found. */ - if (($text[$i] === '=') && - (($i + 1) < $len) && - ($text[$i +1] === '?')) { - ++$i; - $encoded = $is_encoded = true; - } - } - - /* Check for 8-bit characters or control characters. */ - if (!$encoded) { - $c = ord($text[$i]); - if ($encoded = (($c & 0x80) || ($c < 32))) { - $is_encoded = true; - } - } - break; - } - } - - if (!$is_encoded) { - return $text; - } - - if (is_null($lwsp)) { - $parts[] = array(intval($encoded), $word, $len); - } else { - $parts[] = array(2, $lwsp, $len); - } - - /* Combine parts into MIME encoded string. */ - for ($i = 0, $cnt = count($parts); $i < $cnt; ++$i) { - $val = $parts[$i]; - - switch ($val[0]) { - case 0: - case 2: - $out .= substr($text, $val[1], $val[2]); - break; - - case 1: - $j = $i; - for ($k = $i + 1; $k < $cnt; ++$k) { - switch ($parts[$k][0]) { - case 0: - break 2; - - case 1: - $i = $k; - break; - } - } - - $encode = ''; - for (; $j <= $i; ++$j) { - $encode .= substr($text, $parts[$j][1], $parts[$j][2]); - } - - $delim = '=?' . $charset . '?b?'; - $e_parts = explode( - self::EOL, - rtrim( - chunk_split( - base64_encode($encode), - /* strlen($delim) + 2 = space taken by MIME - * delimiter */ - intval((75 - strlen($delim) + 2) / 4) * 4 - ) - ) - ); - - $tmp = array(); - foreach ($e_parts as $val) { - $tmp[] = $delim . $val . '?='; - } - - $out .= implode(' ', $tmp); - break; - } - } - - return rtrim($out); - } - - /** - * Decodes a MIME encoded (RFC 2047) string. - * - * @param string $string The MIME encoded text. - * - * @return string The decoded text. - */ - public static function decode($string) - { - $old_pos = 0; - $out = ''; - - while (($pos = strpos($string, '=?', $old_pos)) !== false) { - /* Save any preceding text, if it is not LWSP between two - * encoded words. */ - $pre = substr($string, $old_pos, $pos - $old_pos); - if (!$old_pos || - (strspn($pre, " \t\n\r") != strlen($pre))) { - $out .= $pre; - } - - /* Search for first delimiting question mark (charset). */ - if (($d1 = strpos($string, '?', $pos + 2)) === false) { - break; - } - - $orig_charset = substr($string, $pos + 2, $d1 - $pos - 2); - if (self::$decodeWindows1252 && - (Horde_String::lower($orig_charset) == 'iso-8859-1')) { - $orig_charset = 'windows-1252'; - } - - /* Search for second delimiting question mark (encoding). */ - if (($d2 = strpos($string, '?', $d1 + 1)) === false) { - break; - } - - $encoding = substr($string, $d1 + 1, $d2 - $d1 - 1); - - /* Search for end of encoded data. */ - if (($end = strpos($string, '?=', $d2 + 1)) === false) { - break; - } - - $encoded_text = substr($string, $d2 + 1, $end - $d2 - 1); - - switch ($encoding) { - case 'Q': - case 'q': - $out .= Horde_String::convertCharset( - quoted_printable_decode( - str_replace('_', ' ', $encoded_text) - ), - $orig_charset, - 'UTF-8' - ); - break; - - case 'B': - case 'b': - $out .= Horde_String::convertCharset( - base64_decode($encoded_text), - $orig_charset, - 'UTF-8' - ); - break; - - default: - // Ignore unknown encoding. - break; - } - - $old_pos = $end + 2; - } - - return $out . substr($string, $old_pos); - } - - /* Deprecated methods. */ - - /** - * @deprecated Use Horde_Mime_Headers_MessageId::create() instead. - */ - public static function generateMessageId() - { - return Horde_Mime_Headers_MessageId::create()->value; - } - - /** - * @deprecated Use Horde_Mime_Uudecode instead. - */ - public static function uudecode($input) - { - $uudecode = new Horde_Mime_Uudecode($input); - return iterator_to_array($uudecode); - } - - /** - * @deprecated - */ - public static $brokenRFC2231 = false; - - /** - * @deprecated - */ - const MIME_PARAM_QUOTED = '/[\x01-\x20\x22\x28\x29\x2c\x2f\x3a-\x40\x5b-\x5d]/'; - - /** - * @deprecated Use Horde_Mime_Headers_ContentParam#encode() instead. - */ - public static function encodeParam($name, $val, array $opts = array()) - { - $cp = new Horde_Mime_Headers_ContentParam( - 'UNUSED', - array($name => $val) - ); - - return $cp->encode(array_merge(array( - 'broken_rfc2231' => self::$brokenRFC2231 - ), $opts)); - } - - /** - * @deprecated Use Horde_Mime_Headers_ELement_ContentParam instead. - */ - public static function decodeParam($type, $data) - { - $cp = new Horde_Mime_Headers_ContentParam( - 'UNUSED', - $data - ); - - if (strlen($cp->value)) { - $val = $cp->value; - } else { - $val = (Horde_String::lower($type) == 'content-type') - ? 'text/plain' - : 'attachment'; - } - - return array( - 'params' => $cp->params, - 'val' => $val - ); - } - - /** - * @deprecated Use Horde_Mime_Id instead. - */ - public static function mimeIdArithmetic($id, $action, $options = array()) - { - $id_ob = new Horde_Mime_Id($id); - - switch ($action) { - case 'down': - $action = $id_ob::ID_DOWN; - break; - - case 'next': - $action = $id_ob::ID_NEXT; - break; - - case 'prev': - $action = $id_ob::ID_PREV; - break; - - case 'up': - $action = $id_ob::ID_UP; - break; - } - - return $id_ob->idArithmetic($action, $options); - } - - /** - * @deprecated Use Horde_Mime_Id instead. - */ - public static function isChild($base, $id) - { - $id_ob = new Horde_Mime_Id($base); - return $id_ob->isChild($id); - } - - /** - * @deprecated Use Horde_Mime_QuotedPrintable instead. - */ - public static function quotedPrintableEncode($text, $eol = self::EOL, - $wrap = 76) - { - return Horde_Mime_QuotedPrintable::encode($text, $eol, $wrap); - } - -} diff --git a/lib/horde/framework/Horde/Mime/ContentParam/Decode.php b/lib/horde/framework/Horde/Mime/ContentParam/Decode.php deleted file mode 100644 index bde49f4a39d..00000000000 --- a/lib/horde/framework/Horde/Mime/ContentParam/Decode.php +++ /dev/null @@ -1,142 +0,0 @@ - - * - * @category Horde - * @copyright 2002-2015 Timo Sirainen - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ - -/** - * Decode MIME content parameter data (RFC 2045; 2183; 2231). - * - * @author Timo Sirainen - * @author Michael Slusarz - * @category Horde - * @copyright 2002-2015 Timo Sirainen - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_ContentParam_Decode extends Horde_Mail_Rfc822 -{ - /** - * Decode content parameter data. - * - * @param string $data Parameter data. - * - * @return array List of parameter key/value combinations. - */ - public function decode($data) - { - $out = array(); - - $this->_data = $data; - $this->_datalen = strlen($data); - $this->_ptr = 0; - - while ($this->_curr() !== false) { - $this->_rfc822SkipLwsp(); - - $this->_rfc822ParseMimeToken($param); - - if (is_null($param) || ($this->_curr() != '=')) { - break; - } - - ++$this->_ptr; - $this->_rfc822SkipLwsp(); - - $value = ''; - - if ($this->_curr() == '"') { - try { - $this->_rfc822ParseQuotedString($value); - } catch (Horde_Mail_Exception $e) { - break; - } - } else { - $this->_rfc822ParseMimeToken($value); - if (is_null($value)) { - break; - } - } - - $out[$param] = $value; - - $this->_rfc822SkipLwsp(); - if ($this->_curr() != ';') { - break; - } - - ++$this->_ptr; - } - - return $out; - } - - /** - * Determine if character is a non-escaped element in MIME parameter data - * (See RFC 2045 [Appendix A]). - * - * @param string $c Character to test. - * - * @return boolean True if non-escaped character. - */ - public static function isAtextNonTspecial($c) - { - switch ($ord = ord($c)) { - case 34: - case 40: - case 41: - case 44: - case 47: - case 58: - case 59: - case 60: - case 61: - case 62: - case 63: - case 64: - case 91: - case 92: - case 93: - /* "(),/:;<=>?@[\] */ - return false; - - default: - /* CTLs, SPACE, DEL, non-ASCII */ - return (($ord > 32) && ($ord < 127)); - } - } - - /** - */ - protected function _rfc822ParseMimeToken(&$str) - { - for ($i = $this->_ptr, $size = strlen($this->_data); $i < $size; ++$i) { - if (!self::isAtextNonTspecial($this->_data[$i])) { - break; - } - } - - if ($i === $this->_ptr) { - $str = null; - } else { - $str = substr($this->_data, $this->_ptr, $i - $this->_ptr); - $this->_ptr += ($i - $this->_ptr); - $this->_rfc822SkipLwsp(); - } - } - -} diff --git a/lib/horde/framework/Horde/Mime/Exception.php b/lib/horde/framework/Horde/Mime/Exception.php deleted file mode 100644 index 64494fa6e4b..00000000000 --- a/lib/horde/framework/Horde/Mime/Exception.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @category Horde - * @copyright 2009-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ -class Horde_Mime_Exception extends Horde_Exception_Wrapped -{ -} diff --git a/lib/horde/framework/Horde/Mime/Filter/Encoding.php b/lib/horde/framework/Horde/Mime/Filter/Encoding.php deleted file mode 100644 index 8c8a0140cc2..00000000000 --- a/lib/horde/framework/Horde/Mime/Filter/Encoding.php +++ /dev/null @@ -1,92 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.6.0 - */ -class Horde_Mime_Filter_Encoding extends php_user_filter -{ - /** - * Number of consecutive non-CR/LF characters. - * - * @var integer - */ - protected $_crlf = 0; - - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function onCreate() - { - $this->params->body = false; - - return true; - } - - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function filter($in, $out, &$consumed, $closing) - { - while ($bucket = stream_bucket_make_writeable($in)) { - if ($this->params->body !== 'binary') { - $len = $bucket->datalen; - $str = $bucket->data; - - for ($i = 0; $i < $len; ++$i) { - $chr = ord($str[$i]); - - switch ($chr) { - case 0: - /* Only binary data can have NULLs. */ - $this->params->body = 'binary'; - break 2; - - case 10: // LF - case 13: // CR - $this->_crlf = 0; - break; - - default: - /* RFC 2045 [2.8]: 8bit data must be less than 998 - * characters in length. Otherwise, we are looking at - * binary. */ - if (++$this->_crlf > 998) { - $this->params->body = 'binary'; - break 2; - } elseif ($chr > 127) { - $this->params->body = '8bit'; - } - break; - } - } - } - - $consumed += $bucket->datalen; - stream_bucket_append($out, $bucket); - } - - return PSFS_PASS_ON; - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers.php b/lib/horde/framework/Horde/Mime/Headers.php deleted file mode 100644 index b801ab6a30f..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers.php +++ /dev/null @@ -1,561 +0,0 @@ - - * @category Horde - * @copyright 2002-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ -class Horde_Mime_Headers -implements ArrayAccess, IteratorAggregate, Serializable -{ - /* Serialized version. */ - const VERSION = 3; - - /** - * The default charset to use when parsing text parts with no charset - * information. - * - * @todo Make this a non-static property or pass as parameter to static - * methods in Horde 6. - * @var string - */ - public static $defaultCharset = 'us-ascii'; - - /** - * Cached handler information for Header Element objects. - * - * @var array - */ - protected static $_handlers = array(); - - /** - * The internal headers array. - * - * @var Horde_Support_CaseInsensitiveArray - */ - protected $_headers; - - /** - * Constructor. - */ - public function __construct() - { - $this->_headers = new Horde_Support_CaseInsensitiveArray(); - } - - /** - */ - public function __clone() - { - $copy = new Horde_Support_CaseInsensitiveArray(); - foreach ($this->_headers as $key => $val) { - $copy[$key] = clone $val; - } - $this->_headers = $copy; - } - - /** - * Returns the headers in array format. - * - * @param array $opts Optional parameters: - *
-     *   - broken_rfc2231: (boolean) Attempt to work around non-RFC
-     *                     2231-compliant MUAs by generating both a RFC
-     *                     2047-like parameter name and also the correct RFC
-     *                     2231 parameter
-     *                     DEFAULT: false
-     *   - canonical: (boolean) Use canonical (RFC 822/2045) CRLF EOLs?
-     *                DEFAULT: Uses "\n"
-     *   - charset: (string) Encodes the headers using this charset. If empty,
-     *              encodes using UTF-8.
-     *              DEFAULT: No encoding.
-     *   - defserver: (string) The default domain to append to mailboxes.
-     *                DEFAULT: No default name.
-     *   - lang: (string) The language to use when encoding.
-     *           DEFAULT: None specified
-     *   - nowrap: (integer) Don't wrap the headers.
-     *             DEFAULT: Headers are wrapped.
-     * 
- * - * @return array The headers in array format. Keys are header names, but - * case sensitivity cannot be guaranteed. Values are - * header values. - */ - public function toArray(array $opts = array()) - { - $charset = array_key_exists('charset', $opts) - ? (empty($opts['charset']) ? 'UTF-8' : $opts['charset']) - : null; - $eol = empty($opts['canonical']) - ? $this->_eol - : "\r\n"; - $ret = array(); - - foreach ($this->_headers as $ob) { - $sopts = array( - 'charset' => $charset - ); - - if (($ob instanceof Horde_Mime_Headers_Addresses) || - ($ob instanceof Horde_Mime_Headers_AddressesMulti)) { - if (!empty($opts['defserver'])) { - $sopts['defserver'] = $opts['defserver']; - } - } elseif ($ob instanceof Horde_Mime_Headers_ContentParam) { - $sopts['broken_rfc2231'] = !empty($opts['broken_rfc2231']); - if (!empty($opts['lang'])) { - $sopts['lang'] = $opts['lang']; - } - } - - $tmp = array(); - - foreach ($ob->sendEncode(array_filter($sopts)) as $val) { - if (empty($opts['nowrap'])) { - /* Remove any existing linebreaks and wrap the line. */ - $htext = $ob->name . ': '; - $val = ltrim( - substr( - wordwrap( - $htext . strtr(trim($val), array("\r" => '', "\n" => '')), - 76, - $eol . ' ' - ), - strlen($htext) - ) - ); - } - - $tmp[] = $val; - } - - $ret[$ob->name] = (count($tmp) == 1) - ? reset($tmp) - : $tmp; - } - - return $ret; - } - - /** - * Returns all headers concatenated into a single string. - * - * @param array $opts See toArray(). - * - * @return string The headers in string format. - */ - public function toString(array $opts = array()) - { - $eol = empty($opts['canonical']) - ? $this->_eol - : "\r\n"; - $text = ''; - - foreach ($this->toArray($opts) as $key => $val) { - foreach ((is_array($val) ? $val : array($val)) as $entry) { - $text .= $key . ': ' . $entry . $eol; - } - } - - return $text . $eol; - } - - /** - * Add/append/replace a header. - * - * @param string $header The header name. - * @param string $value The header value (UTF-8). - * @param array $opts DEPRECATED - */ - public function addHeader($header, $value, array $opts = array()) - { - /* Existing header? Add to that object. */ - $header = trim($header); - if ($hdr = $this[$header]) { - $hdr->setValue($value); - return; - } - - $classname = $this->_getHeaderClassName($header); - - try { - $ob = new $classname($header, $value); - } catch (InvalidArgumentException $e) { - /* Ignore an invalid header. */ - return; - } catch (Horde_Mime_Exception $e) { - return; - } - - switch ($classname) { - case 'Horde_Mime_Headers_ContentParam_ContentDisposition': - case 'Horde_Mime_Headers_ContentParam_ContentType': - /* BC */ - if (!empty($opts['params'])) { - foreach ($opts['params'] as $key => $val) { - $ob[$key] = $val; - } - } - break; - } - - $this->_headers[$ob->name] = $ob; - } - - /** - * Add a Horde_Mime_Headers_Element object to the current header list. - * - * @since 2.5.0 - * - * @param Horde_Mime_Headers_Element $ob Header object to add. - * @param boolean $check Check that the header and object - * type match? - * - * @throws InvalidArgumentException - */ - public function addHeaderOb(Horde_Mime_Headers_Element $ob, $check = false) - { - if ($check) { - $cname = $this->_getHeaderClassName($ob->name); - if (!($ob instanceof $cname)) { - throw new InvalidArgumentException(sprintf( - 'Object is not correct class: %s', - $cname - )); - } - } - - /* Existing header? Add to that object. */ - if ($hdr = $this[$ob->name]) { - $hdr->setValue($ob); - } else { - $this->_headers[$ob->name] = $ob; - } - } - - /** - * Return the header class to use for a header name. - * - * @param string $header The header name. - * - * @return string The Horde_Mime_Headers_* class to use. - */ - protected function _getHeaderClassName($header) - { - if (empty(self::$_handlers)) { - $search = array( - 'Horde_Mime_Headers_Element_Single', - 'Horde_Mime_Headers_AddressesMulti', - 'Horde_Mime_Headers_Addresses', - 'Horde_Mime_Headers_ContentDescription', - 'Horde_Mime_Headers_ContentId', - 'Horde_Mime_Headers_ContentLanguage', - 'Horde_Mime_Headers_ContentParam_ContentDisposition', - 'Horde_Mime_Headers_ContentParam_ContentType', - 'Horde_Mime_Headers_ContentTransferEncoding', - 'Horde_Mime_Headers_Date', - 'Horde_Mime_Headers_Identification', - 'Horde_Mime_Headers_MessageId', - 'Horde_Mime_Headers_Mime', - 'Horde_Mime_Headers_MimeVersion', - 'Horde_Mime_Headers_Received', - 'Horde_Mime_Headers_Subject', - 'Horde_Mime_Headers_UserAgent' - ); - - foreach ($search as $val) { - foreach ($val::getHandles() as $hdr) { - self::$_handlers[$hdr] = $val; - } - } - } - - $header = Horde_String::lower($header); - - return isset(self::$_handlers[$header]) - ? self::$_handlers[$header] - : 'Horde_Mime_Headers_Element_Multiple'; - } - - /** - * Get a header from the header array. - * - * @param string $header The header name. - * - * @return Horde_Mime_Headers_Element Element object, or null if not - * found. - */ - public function getHeader($header) - { - return $this[$header]; - } - - /** - * Remove a header from the header array. - * - * @param string $header The header name. - */ - public function removeHeader($header) - { - unset($this[$header]); - } - - /* Static methods. */ - - /** - * Builds a Horde_Mime_Headers object from header text. - * - * @param mixed $text A text string (or, as of 2.3.0, a Horde_Stream - * object or stream resource) containing the headers. - * - * @return Horde_Mime_Headers A new Horde_Mime_Headers object. - */ - public static function parseHeaders($text) - { - $curr = null; - $headers = new Horde_Mime_Headers(); - $hdr_list = array(); - - if ($text instanceof Horde_Stream) { - $stream = $text; - $stream->rewind(); - } else { - $stream = new Horde_Stream_Temp(); - $stream->add($text, true); - } - - while (!$stream->eof()) { - if (!($val = rtrim($stream->getToChar("\n", false), "\r"))) { - break; - } - - if ($curr && (($val[0] == ' ') || ($val[0] == "\t"))) { - $curr->text .= ' ' . ltrim($val); - } else { - $pos = strpos($val, ':'); - - $curr = new stdClass; - $curr->header = substr($val, 0, $pos); - $curr->text = ltrim(substr($val, $pos + 1)); - - $hdr_list[] = $curr; - } - } - - foreach ($hdr_list as $val) { - /* When parsing, only keep the FIRST header seen for single value - * text-only headers, since newer headers generally are appended - * to the top of the message. */ - if (!($ob = $headers[$val->header]) || - !($ob instanceof Horde_Mime_Headers_Element_Single) || - ($ob instanceof Horde_Mime_Headers_Addresses)) { - $headers->addHeader($val->header, rtrim($val->text)); - } - } - - if (!($text instanceof Horde_Stream)) { - $stream->close(); - } - - return $headers; - } - - /* Serializable methods. */ - - /** - * Serialization. - * - * @return string Serialized data. - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - * Serialization. - * - * @return array Serialized data. - */ - public function __serialize(): array - { - return array( - // Serialized data ID. - self::VERSION, - $this->_headers->getArrayCopy(), - // TODO: BC - $this->_eol - ); - } - - /** - * Unserialization. - * - * @param array $data Serialized data. - * - * @throws Horde_Mime_Exception - */ - public function __unserialize(array $data): void - { - if (!isset($data[0]) || ($data[0] != self::VERSION)) { - throw new Horde_Mime_Exception('Cache version change'); - } - - $this->_headers = new Horde_Support_CaseInsensitiveArray($data[1]); - // TODO: BC - $this->_eol = $data[2]; - } - - /** - * Unserialization. - * - * @param string $data Serialized data. - * - * @throws Exception - */ - public function unserialize($data) - { - $data = @unserialize($data); - if (!is_array($data)) { - throw new Horde_Mime_Exception('Cache version change'); - } - $this->__unserialize($data); - } - - /* ArrayAccess methods. */ - - /** - * Does header exist? - * - * @since 2.5.0 - * - * @param string $header Header name. - * - * @return boolean True if header exists. - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) - { - return isset($this->_headers[trim($offset)]); - } - - /** - * Return header element object. - * - * @since 2.5.0 - * - * @param string $header Header name. - * - * @return Horde_Mime_Headers_Element Element object, or null if not - * found. - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - return $this->_headers[trim($offset)]; - } - - /** - * Store a header element object. - * - * @since 2.5.0 - * - * @param string $offset Not used. - * @param Horde_Mime_Headers_Element $elt Header element. - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - $this->addHeaderOb($value); - } - - /** - * Remove a header element object. - * - * @since 2.5.0 - * - * @param string $offset Header name. - */ - #[ReturnTypeWillChange] - public function offsetUnset($offset) - { - unset($this->_headers[trim($offset)]); - } - - /* IteratorAggregate function */ - - /** - * @since 2.5.0 - */ - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_headers); - } - - /* Deprecated functions */ - - /** - * Handle deprecated methods. - */ - public function __call($name, $arguments) - { - $d = new Horde_Mime_Headers_Deprecated($this); - return call_user_func_array(array($d, $name), $arguments); - } - - /** - * Handle deprecated static methods. - */ - public static function __callStatic($name, $arguments) - { - $d = new Horde_Mime_Headers_Deprecated(); - return call_user_func_array(array($d, $name), $arguments); - } - - /** - * @deprecated - */ - protected $_eol = "\n"; - - /** - * @deprecated - */ - public function setEOL($eol) - { - $this->_eol = $eol; - } - - /** - * @deprecated - */ - public function getEOL() - { - return $this->_eol; - } - - /* Constants for getValue(). @deprecated */ - const VALUE_STRING = 1; - const VALUE_BASE = 2; - const VALUE_PARAMS = 3; - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Addresses.php b/lib/horde/framework/Horde/Mime/Headers/Addresses.php deleted file mode 100644 index 7d65a8ccb20..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Addresses.php +++ /dev/null @@ -1,176 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Headers_Addresses -extends Horde_Mime_Headers_Element_Single -implements Horde_Mime_Headers_Element_Address -{ - /** - * By default, if more than 1 address header is found, the addresses are - * appended together into a single field. Set this value to false to - * ignore all but the *last* header. - * - * @var boolean - */ - public $append_addr = true; - - /** - */ - public function __clone() - { - $this->_values = clone $this->_values; - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'full_value': - case 'value': - case 'value_single': - return strval($this->_values); - } - - return parent::__get($name); - } - - /** - */ - public function getAddressList($first = false) - { - return $first - ? $this->_values - : array($this->_values); - } - - /** - * - * @throws Horde_Mime_Exception - */ - protected function _setValue($value) - { - /* @todo Implement with traits */ - $rfc822 = new Horde_Mail_Rfc822(); - - try { - $addr_list = $rfc822->parseAddressList($value); - } catch (Horde_Mail_Exception $e) { - throw new Horde_Mime_Exception($e); - } - - foreach ($addr_list as $ob) { - if ($ob instanceof Horde_Mail_Rfc822_Group) { - $ob->groupname = $this->_sanityCheck($ob->groupname); - } else { - $ob->personal = $this->_sanityCheck($ob->personal); - } - } - - switch (Horde_String::lower($this->name)) { - 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; - } - - if ($this->append_addr && $this->_values) { - $this->_values->add($addr_list); - } else { - $this->_values = $addr_list; - } - } - - /** - */ - public static function getHandles() - { - return array( - // Mail: RFC 3798 - 'disposition-notification-to', - // Mail: RFC 5322 (Address) - 'from', - 'to', - 'cc', - 'bcc', - 'reply-to', - 'sender' - ); - } - - /** - * @param array $opts See doSendEncode(). - */ - protected function _sendEncode($opts) - { - return self::doSendEncode($this->getAddressList(), $opts); - } - - /** - * Do send encoding for addresses. - * - * Needed as a static function because it is used by both single and - * multiple address headers. - * - * @todo Implement with traits. - * - * @param array $alist An array of Horde_Mail_Rfc822_List objects. - * @param array $opts Additional options: - * - charset: (string) Encodes the headers using this charset. - * DEFAULT: UTF-8 - * - defserver: (string) The default domain to append to mailboxes. - * DEFAULT: No default name. - * - idn: (boolean) Encode IDN domain names (RFC 3490) if true. - * DEFAULT: true - */ - public static function doSendEncode($alist, array $opts = array()) - { - $out = array(); - $opts = array_merge(array('idn' => true), $opts); - foreach ($alist as $ob) { - if (!empty($opts['defserver'])) { - foreach ($ob->raw_addresses as $ob2) { - if (is_null($ob2->host)) { - $ob2->host = $opts['defserver']; - } - } - } - - $out[] = $ob->writeAddress(array( - 'encode' => empty($opts['charset']) ? null : $opts['charset'], - 'idn' => $opts['idn'] - )); - } - - return $out; - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/AddressesMulti.php b/lib/horde/framework/Horde/Mime/Headers/AddressesMulti.php deleted file mode 100644 index be4784b8256..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/AddressesMulti.php +++ /dev/null @@ -1,107 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Headers_AddressesMulti -extends Horde_Mime_Headers_Element_Multiple -implements Horde_Mime_Headers_Element_Address -{ - /** - */ - public function __clone() - { - $copy = array(); - foreach ($this->_values as $val) { - $copy[] = clone $val; - } - $this->_values = $copy; - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'full_value': - case 'value': - return array_map('strval', $this->_values); - - case 'value_single': - return strval(reset($this->_values)); - } - - return parent::__get($name); - } - - /** - */ - public function getAddressList($first = false) - { - return $first - ? reset($this->_values) - : $this->_values; - } - - /** - */ - protected function _setValue($value) - { - /* @todo Implement with traits */ - $rfc822 = new Horde_Mail_Rfc822(); - $addr_list = $rfc822->parseAddressList($value); - - foreach ($addr_list as $ob) { - if ($ob instanceof Horde_Mail_Rfc822_Group) { - $ob->groupname = $this->_sanityCheck($ob->groupname); - } else { - $ob->personal = $this->_sanityCheck($ob->personal); } - } - - $this->_values[] = $addr_list; - } - - /** - */ - public static function getHandles() - { - return array( - // Mail: RFC 5322 (Address that can appear in multiple headers) - 'resent-to', - 'resent-cc', - 'resent-bcc', - 'resent-from' - ); - } - - /** - * @param array $opts See Horde_Mime_Headers_Addresses#doSendEncode(). - */ - protected function _sendEncode($opts) - { - return Horde_Mime_Headers_Addresses::doSendEncode( - $this->getAddressList(), - $opts - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/ContentDescription.php b/lib/horde/framework/Horde/Mime/Headers/ContentDescription.php deleted file mode 100644 index 6ae004541f1..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/ContentDescription.php +++ /dev/null @@ -1,52 +0,0 @@ - - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.7.0 - */ -class Horde_Mime_Headers_ContentDescription -extends Horde_Mime_Headers_Element_Single -implements Horde_Mime_Headers_Extension_Mime -{ - /** - */ - public function __construct($name, $value) - { - parent::__construct('Content-Description', $value); - } - - /** - */ - protected function _sendEncode($opts) - { - return array(Horde_Mime::encode($this->value, $opts['charset'])); - } - - /** - */ - public static function getHandles() - { - return array( - // MIME: RFC 2045 - 'content-description' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/ContentId.php b/lib/horde/framework/Horde/Mime/Headers/ContentId.php deleted file mode 100644 index c8933efdcb8..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/ContentId.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.8.0 - */ -class Horde_Mime_Headers_ContentId -extends Horde_Mime_Headers_Element_Single -implements Horde_Mime_Headers_Extension_Mime -{ - /** - * Creates a Content-ID header conforming to RFC 2045 [7]. - * - * @return Horde_Mime_Headers_ContentId Content-ID header object. - */ - public static function create() - { - return new self( - null, - strval(new Horde_Support_Randomid()) . '@' . gethostname() - ); - } - - /** - */ - public function __construct($name, $value) - { - parent::__construct('Content-ID', $value); - } - - /** - */ - protected function _setValue($value) - { - parent::_setValue($value); - - $val = $this->value; - $cid = '<' . ltrim(rtrim($val, '>'), '<') . '>'; - - if ($cid !== $val) { - parent::_setValue($cid); - } - } - - /** - */ - public static function getHandles() - { - return array( - 'content-id' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/ContentLanguage.php b/lib/horde/framework/Horde/Mime/Headers/ContentLanguage.php deleted file mode 100644 index 904cc02cc85..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/ContentLanguage.php +++ /dev/null @@ -1,84 +0,0 @@ - - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.8.0 - * - * @property-read array $langs The list of languages. - */ -class Horde_Mime_Headers_ContentLanguage -extends Horde_Mime_Headers_Element_Single -implements Horde_Mime_Headers_Extension_Mime -{ - /** - */ - public function __construct($name, $value) - { - parent::__construct('Content-Language', $value); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'full_value': - case 'value': - case 'value_single': - return implode(',', $this->_values); - - case 'langs': - return $this->_values; - } - - return parent::__get($name); - } - - /** - * @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 static function getHandles() - { - return array( - 'content-language' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/ContentParam.php b/lib/horde/framework/Horde/Mime/Headers/ContentParam.php deleted file mode 100644 index 4d18c34f918..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/ContentParam.php +++ /dev/null @@ -1,457 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - * - * @property-read array $params Content parameters. - */ -class Horde_Mime_Headers_ContentParam -extends Horde_Mime_Headers_Element_Single -implements ArrayAccess, Horde_Mime_Headers_Extension_Mime, Serializable -{ - /** - * Content parameters. - * - * @var Horde_Support_CaseInsensitiveArray - */ - protected $_params; - - /** - */ - public function __clone() - { - $this->_params = new Horde_Support_CaseInsensitiveArray( - $this->_params->getArrayCopy() - ); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'full_value': - $tmp = $this->value; - foreach ($this->_escapeParams($this->params) as $key => $val) { - $tmp .= '; ' . $key . '=' . $val; - } - return $tmp; - - case 'params': - return $this->_params->getArrayCopy(); - } - - return parent::__get($name); - } - - /** - * @param mixed $data Either an array (interpreted as a list of - * parameters), a string (interpreted as a RFC - * encoded parameter list), an object with two - * properties: value and params, or a - * Horde_Mime_Headers_ContentParam object. - */ - protected function _setValue($data) - { - if (!$this->_params) { - $this->_params = new Horde_Support_CaseInsensitiveArray(); - } - - if ($data instanceof Horde_Mime_Headers_ContentParam) { - if (empty($this->_values)) { - $this->setContentParamValue($data->value); - } - foreach ($data->params as $key => $val) { - $this[$key] = $val; - } - } elseif (is_object($data)) { - if (!empty($data->value)) { - $this->setContentParamValue($data->value); - } - if (!empty($data->params)) { - $this->decode($data->params); - } - } else { - $this->decode($data); - } - } - - /** - * @param array $opts See encode(). - */ - protected function _sendEncode($opts) - { - $out = $this->value; - - foreach ($this->encode($opts) as $key => $val) { - $out .= '; ' . $key . '=' . $val; - } - - return array($out); - } - - /** - */ - public static function getHandles() - { - return array(); - } - - /** - * Encodes a MIME content parameter string pursuant to RFC 2183 & 2231 - * (Content-Type and Content-Disposition headers). - * - * @param array $opts Options: - * - broken_rfc2231: (boolean) Attempt to work around non-RFC - * 2231-compliant MUAs by generating both a RFC - * 2047-like parameter name and also the correct RFC - * 2231 parameter - * DEFAULT: false - * - charset: (string) The charset to encode to. - * DEFAULT: UTF-8 - * - lang: (string) The language to use when encoding. - * DEFAULT: None specified - * - * @return array The encoded parameter string (US-ASCII). - */ - public function encode(array $opts = array()) - { - $opts = array_merge(array( - 'charset' => 'UTF-8', - ), $opts); - - $out = array(); - - foreach ($this->params as $key => $val) { - $out = array_merge($out, $this->_encode($key, $val, $opts)); - } - - return $out; - } - - /** - * @see encode() - */ - protected function _encode($name, $val, $opts) - { - $curr = 0; - $encode = $wrap = false; - $out = array(); - - // 2 = '=', ';' - $pre_len = strlen($name) + 2; - - /* Several possibilities: - * - String is ASCII. Output as ASCII (duh). - * - Language information has been provided. We MUST encode output - * to include this information. - * - String is non-ASCII, but can losslessly translate to ASCII. - * Output as ASCII (most efficient). - * - String is in non-ASCII, but doesn't losslessly translate to - * ASCII. MUST encode output (duh). */ - if (empty($opts['lang']) && !Horde_Mime::is8bit($val, 'UTF-8')) { - $string = $val; - } else { - $cval = Horde_String::convertCharset($val, 'UTF-8', $opts['charset']); - $string = Horde_String::lower($opts['charset']) . '\'' . (empty($opts['lang']) ? '' : Horde_String::lower($opts['lang'])) . '\'' . rawurlencode($cval); - $encode = true; - /* Account for trailing '*'. */ - ++$pre_len; - } - - if (($pre_len + strlen($string)) > 75) { - /* Account for continuation '*'. */ - ++$pre_len; - $wrap = true; - - while ($string) { - $chunk = 75 - $pre_len - strlen($curr); - $pos = min($chunk, strlen($string) - 1); - - /* Don't split in the middle of an encoded char. */ - if (($chunk == $pos) && ($pos > 2)) { - for ($i = 0; $i <= 2; ++$i) { - if ($string[$pos - $i] == '%') { - $pos -= $i + 1; - break; - } - } - } - - $lines[] = substr($string, 0, $pos + 1); - $string = substr($string, $pos + 1); - ++$curr; - } - } else { - $lines = array($string); - } - - foreach ($lines as $i => $line) { - $out[$name . (($wrap) ? ('*' . $i) : '') . (($encode) ? '*' : '')] = $line; - } - - if (!empty($opts['broken_rfc2231']) && !isset($out[$name])) { - $out = array_merge(array( - $name => Horde_Mime::encode($val, $opts['charset']) - ), $out); - } - - /* Escape characters in params (See RFC 2045 [Appendix A]). - * Must be quoted-string if one of these exists. */ - return $this->_escapeParams($out); - } - - /** - * Escape the parameter array. - * - * @param array $params Parameter array. - * - * @return array Escaped parameter array. - */ - protected function _escapeParams($params) - { - foreach ($params as $k => $v) { - foreach (str_split($v) as $c) { - if (!Horde_Mime_ContentParam_Decode::isAtextNonTspecial($c)) { - $params[$k] = '"' . addcslashes($v, '\\"') . '"'; - break; - } - } - } - - return $params; - } - - /** - * Set the content-parameter base value. - * - * @since 2.8.0 - * - * @param string $data Value. - */ - public function setContentParamValue($data) - { - $data = $this->_sanityCheck(trim($data)); - if (($pos = strpos($data, ';')) !== false) { - $data = substr($data, 0, $pos); - } - - $this->_values = array($data); - } - - /** - * 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]); - } - } - - /* ArrayAccess methods */ - - /** - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) - { - return isset($this->_params[$offset]); - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - return $this->_params[$offset]; - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - $this->_params[$offset] = $this->_sanityCheck($value); - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetUnset($offset) - { - unset($this->_params[$offset]); - } - - /* Serializable methods */ - - /** - * Serialize (until PHP 7.3) - * - * @return string serialized object state - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - * Serialize (PHP 7.4+) - * - * @return array object state - */ - public function __serialize(): array - { - $vars = array_filter(get_object_vars($this)); - if (isset($vars['_params'])) { - $vars['_params'] = $vars['_params']->getArrayCopy(); - } - return $vars; - } - - /** - * Unserialize (PHP 7.4+) - * - * @param array $data - */ - public function __unserialize(array $data): void - { - foreach ($data as $key => $val) { - switch ($key) { - case '_params': - $this->_params = new Horde_Support_CaseInsensitiveArray($val); - break; - - default: - $this->$key = $val; - break; - } - } - } - - /** - * Unserialize (until PHP 7.3) - * - * @param string $data - */ - public function unserialize($data) - { - $this->__unserialize(unserialize($data)); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/ContentParam/ContentDisposition.php b/lib/horde/framework/Horde/Mime/Headers/ContentParam/ContentDisposition.php deleted file mode 100644 index 6439a663e85..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/ContentParam/ContentDisposition.php +++ /dev/null @@ -1,104 +0,0 @@ - - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.8.0 - */ -class Horde_Mime_Headers_ContentParam_ContentDisposition -extends Horde_Mime_Headers_ContentParam -{ - /** - */ - public function __construct($name, $value) - { - parent::__construct('Content-Disposition', $value); - } - - /** - */ - public function __get($name) - { - $val = parent::__get($name); - - switch ($name) { - case 'full_value': - $val = parent::__get($name); - if (substr(ltrim($val), 0, 1) === ';') { - $val = 'attachment' . $val; - } - break; - } - - return $val; - } - - /** - */ - public function setContentParamValue($data) - { - parent::setContentParamValue($data); - - if (strlen($val = $this->value)) { - if (strcasecmp($val, 'attachment') === 0) { - $val2 = 'attachment'; - } elseif (strcasecmp($val, 'inline') === 0) { - $val2 = 'inline'; - } else { - $val2 = ''; - } - - if ($val !== $val2) { - parent::setContentParamValue($val2); - } - } - } - - /** - */ - public function isDefault() - { - return !($this->full_value); - } - - /** - */ - public static function getHandles() - { - return array( - 'content-disposition' - ); - } - - /* ArrayAccess methods */ - - /** - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - if (strcasecmp($offset, 'size') === 0) { - // RFC 2183 [2.7] - size parameter - $value = intval($this->_sanityCheck($value)); - } - - parent::offsetSet($offset, $value); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/ContentParam/ContentType.php b/lib/horde/framework/Horde/Mime/Headers/ContentParam/ContentType.php deleted file mode 100644 index 274551bf337..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/ContentParam/ContentType.php +++ /dev/null @@ -1,198 +0,0 @@ - - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.8.0 - * - * @property-read string $ptype The primary type. - * @property-read string $stype The sub type. - * @property-read string $type_charset The MIME type with the charset - * parameter added (if this is a text/* - * part). - */ -class Horde_Mime_Headers_ContentParam_ContentType -extends Horde_Mime_Headers_ContentParam -{ - const DEFAULT_CONTENT_TYPE = 'application/octet-stream'; - - /** - * Creates a default Content-Type header, conforming to the MIME - * specification as detailed in RFC 2045. - * - * @return Horde_Mime_Headers_ContentParam_ContentType Content-Type - * header object. - */ - public static function create() - { - $ob = new stdClass; - $ob->value = self::DEFAULT_CONTENT_TYPE; - - return new self(null, $ob); - } - - /** - */ - public function __construct($name, $value) - { - parent::__construct('Content-Type', $value); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'params': - $params = new Horde_Support_CaseInsensitiveArray( - parent::__get($name) - ); - foreach ($params as $key => $val) { - if (!isset($this[$key])) { - unset($params[$key]); - } - } - return $params->getArrayCopy(); - - case 'ptype': - $val = $this->value; - return substr($val, 0, strpos($val, '/')); - - case 'stype': - $val = $this->value; - return substr($val, strpos($val, '/') + 1); - - case 'type_charset': - $val = $this->value; - foreach ($this->_escapeParams(array_filter(array('charset' => $this['charset']))) as $k2 => $v2) { - $val .= '; ' . $k2 . '=' . $v2; - } - return $val; - } - - return parent::__get($name); - } - - /** - */ - public function setContentParamValue($data) - { - /* Set the value first, since it will handle any sanity checking. */ - parent::setContentParamValue(Horde_String::lower($data)); - - $val = $this->value; - - if (strpos($val, '/') === false) { - parent::setContentParamValue(self::DEFAULT_CONTENT_TYPE); - } else { - switch ($this->ptype) { - case 'multipart': - if (!isset($this['boundary'])) { - $this['boundary'] = '=_' . new Horde_Support_Randomid(); - } - break; - - case 'application': - case 'audio': - case 'image': - case 'message': - case 'model': - case 'text': - case 'video': - // No-op - break; - - default: - if (substr($val, 0, 2) !== 'x-') { - /* Append 'x-' for any unknown primary MIME type. */ - parent::setContentParamValue('x-' . $val); - } - break; - } - } - } - - /** - */ - public function isDefault() - { - return ($this->full_value === 'text/plain'); - } - - /** - */ - public static function getHandles() - { - return array( - 'content-type' - ); - } - - /* ArrayAccess methods. */ - - /** - */ - public function offsetExists($offset) - { - if (!parent::offsetExists($offset)) { - return false; - } - - if (strcasecmp($offset, 'boundary') === 0) { - return ($this->ptype === 'multipart'); - } elseif (strcasecmp($offset, 'charset') === 0) { - return (($this->ptype === 'text') && - (parent::offsetGet($offset) !== 'us-ascii')); - } - - return true; - } - - /** - */ - public function offsetGet($offset) - { - return isset($this[$offset]) - ? parent::offsetGet($offset) - : null; - } - - /** - */ - public function offsetSet($offset, $value) - { - /* Store character set as lower case value. */ - if (strcasecmp($offset, 'charset') === 0) { - $value = Horde_String::lower($value); - } - - parent::offsetSet($offset, $value); - } - - /** - */ - public function offsetUnset($offset) - { - if (($this->ptype !== 'multipart') || - (strcasecmp($offset, 'boundary') !== 0)) { - parent::offsetUnset($offset); - } - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/ContentTransferEncoding.php b/lib/horde/framework/Horde/Mime/Headers/ContentTransferEncoding.php deleted file mode 100644 index 94557b2c339..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/ContentTransferEncoding.php +++ /dev/null @@ -1,95 +0,0 @@ - - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.8.0 - */ -class Horde_Mime_Headers_ContentTransferEncoding -extends Horde_Mime_Headers_Element_Single -implements Horde_Mime_Headers_Extension_Mime -{ - /** Default encoding (RFC 2045 [6.1]). */ - const DEFAULT_ENCODING = '7bit'; - - /** Unknown encoding specifier. */ - const UNKNOWN_ENCODING = 'x-unknown'; - - /** - */ - public function __construct($name, $value) - { - if (!strlen($value)) { - $value = self::DEFAULT_ENCODING; - } - - parent::__construct('Content-Transfer-Encoding', $value); - } - - /** - */ - protected function _setValue($value) - { - parent::_setValue(trim($value)); - - $val = $this->value; - $encoding = Horde_String::lower($val); - - switch ($encoding) { - case '7bit': - case '8bit': - case 'base64': - case 'binary': - case 'quoted-printable': - // Valid encodings - break; - - default: - /* RFC 2045 [6.3] - Valid non-standardized encodings must begin - * with 'x-'. */ - if (substr($encoding, 0, 2) !== 'x-') { - $encoding = self::UNKNOWN_ENCODING; - } - break; - } - - if ($encoding !== $val) { - parent::_setValue($encoding); - } - } - - /** - */ - public function isDefault() - { - return ($this->value === self::DEFAULT_ENCODING); - } - - /** - */ - public static function getHandles() - { - return array( - // MIME: RFC 2045 - 'content-transfer-encoding' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Date.php b/lib/horde/framework/Horde/Mime/Headers/Date.php deleted file mode 100644 index 157ffd9fc4a..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Date.php +++ /dev/null @@ -1,75 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Headers_Date -extends Horde_Mime_Headers_Element_Single -{ - /** - * Generate a 'Date' header for the current time. - * - * @return Horde_Mime_Headers_Date Date header object. - */ - public static function create() - { - return new self(null, date('r')); - } - - /** - */ - public function __construct($name, $value) - { - parent::__construct('Date', $value); - } - - /** - */ - public static function getHandles() - { - return array( - // Mail: RFC 5322 - 'date' - ); - } - - /** - * Perform sanity checking on a header value. - * - * @param string $data The header data. - * - * @return string The cleaned header data. - */ - protected function _sanityCheck($data) - { - $date = parent::_sanityCheck($data); - if (substr(rtrim($date), -5) === ' 0000') { - $date = substr(trim($date), 0, strlen(trim($date)) - 5) . ' +0000'; - } - - /* Check for malformed day-of-week parts */ - if (!preg_match("/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun),/", $date)) { - $date = trim(preg_replace("/^(\S*,)/", '', $date)); - } - - return $date; - } -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Deprecated.php b/lib/horde/framework/Horde/Mime/Headers/Deprecated.php deleted file mode 100644 index 36d8f39ae62..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Deprecated.php +++ /dev/null @@ -1,263 +0,0 @@ - - * @deprecated - * @category Horde - * @copyright 2014-2016 Horde LLC - * @internal - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Headers_Deprecated -{ - /** - * Base headers object. - * - * @var Horde_Mime_Headers - */ - private $_headers; - - /** - */ - public function __construct(Horde_Mime_Headers $headers) - { - $this->_headers = $headers; - } - - /** - */ - public function addMessageIdHeader() - { - $this->_headers->addHeaderOb(Horde_Mime_Headers_MessageId::create()); - } - - /** - */ - public function addUserAgentHeader() - { - $this->_headers->addHeaderOb(Horde_Mime_Headers_UserAgent::create()); - } - - /** - */ - public function getUserAgent() - { - return strval(Horde_Mime_Headers_UserAgent::create()); - } - - /** - */ - public function setUserAgent($agent) - { - $this->_headers->addHeaderOb( - new Horde_Mime_Headers_UserAgent(null, $agent) - ); - } - - /** - */ - public function addReceivedHeader(array $opts = array()) - { - $old_error = error_reporting(0); - if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { - /* This indicates the user is connecting through a proxy. */ - $remote_path = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); - $remote_addr = $remote_path[0]; - if (!empty($opts['dns'])) { - $remote = $remote_addr; - try { - if ($response = $opts['dns']->query($remote_addr, 'PTR')) { - foreach ($response->answer as $val) { - if (isset($val->ptrdname)) { - $remote = $val->ptrdname; - break; - } - } - } - } catch (Net_DNS2_Exception $e) {} - } else { - $remote = gethostbyaddr($remote_addr); - } - } else { - $remote_addr = $_SERVER['REMOTE_ADDR']; - if (empty($_SERVER['REMOTE_HOST'])) { - if (!empty($opts['dns'])) { - $remote = $remote_addr; - try { - if ($response = $opts['dns']->query($remote_addr, 'PTR')) { - foreach ($response->answer as $val) { - if (isset($val->ptrdname)) { - $remote = $val->ptrdname; - break; - } - } - } - } catch (Net_DNS2_Exception $e) {} - } else { - $remote = gethostbyaddr($remote_addr); - } - } else { - $remote = $_SERVER['REMOTE_HOST']; - } - } - error_reporting($old_error); - - if (!empty($_SERVER['REMOTE_IDENT'])) { - $remote_ident = $_SERVER['REMOTE_IDENT'] . '@' . $remote . ' '; - } elseif ($remote != $_SERVER['REMOTE_ADDR']) { - $remote_ident = $remote . ' '; - } else { - $remote_ident = ''; - } - - if (!empty($opts['server'])) { - $server_name = $opts['server']; - } elseif (!empty($_SERVER['SERVER_NAME'])) { - $server_name = $_SERVER['SERVER_NAME']; - } elseif (!empty($_SERVER['HTTP_HOST'])) { - $server_name = $_SERVER['HTTP_HOST']; - } else { - $server_name = 'unknown'; - } - - $is_ssl = isset($_SERVER['HTTPS']) && - $_SERVER['HTTPS'] != 'off'; - - if ($remote == $remote_addr) { - $remote = '[' . $remote . ']'; - } - - $this->_headers->addHeaderOb(new Horde_Mime_Headers_Element_Multiple( - 'Received', - 'from ' . $remote . ' (' . $remote_ident . - '[' . $remote_addr . ']) ' . - 'by ' . $server_name . ' (Horde Framework) with HTTP' . - ($is_ssl ? 'S' : '') . '; ' . date('r') - )); - } - - /** - */ - public function getOb($field) - { - return ($h = $this->_headers[$field]) - ? $h->getAddressList(true) - : null; - } - - /** - */ - public function getValue($header, $type = Horde_Mime_Headers::VALUE_STRING) - { - if (!($ob = $this->_headers[$header])) { - return null; - } - - switch ($type) { - case Horde_Mime_Headers::VALUE_BASE: - $tmp = $ob->value; - break; - - case Horde_Mime_Headers::VALUE_PARAMS: - return array_change_key_case($ob->params, CASE_LOWER); - - case Horde_Mime_Headers::VALUE_STRING: - $tmp = $ob->full_value; - break; - } - - return (is_array($tmp) && (count($tmp) === 1)) - ? reset($tmp) - : $tmp; - } - - /** - */ - public function listHeaders() - { - $lhdrs = new Horde_ListHeaders(); - return $lhdrs->headers(); - } - - /** - */ - public function listHeadersExist() - { - $lhdrs = new Horde_ListHeaders(); - return $lhdrs->listHeadersExist($this->_headers); - } - - /** - */ - public function replaceHeader($header, $value, array $opts = array()) - { - $this->_headers->removeHeader($header); - $this->_headers->addHeader($header, $value, $opts); - } - - /** - */ - public function getString($header) - { - return (($hdr = $this->_headers[$header]) === null) - ? null - : $this->_headers[$header]->name; - } - - /** - */ - public function addressFields() - { - return array( - 'from', 'to', 'cc', 'bcc', 'reply-to', 'resent-to', 'resent-cc', - 'resent-bcc', 'resent-from', 'sender' - ); - } - - /** - */ - public function singleFields($list = true) - { - $fields = array( - 'to', 'from', 'cc', 'bcc', 'date', 'sender', 'reply-to', - 'message-id', 'in-reply-to', 'references', 'subject', - 'content-md5', 'mime-version', 'content-type', - 'content-transfer-encoding', 'content-id', 'content-description', - 'content-base', 'content-disposition', 'content-duration', - 'content-location', 'content-features', 'content-language', - 'content-alternative', 'importance', 'x-priority' - ); - - $list_fields = array( - 'list-help', 'list-unsubscribe', 'list-subscribe', 'list-owner', - 'list-post', 'list-archive', 'list-id' - ); - - return $list - ? array_merge($fields, $list_fields) - : $fields; - } - - /** - */ - public function mimeParamFields() - { - return array('content-type', 'content-disposition'); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Element.php b/lib/horde/framework/Horde/Mime/Headers/Element.php deleted file mode 100644 index 124cc89fa78..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Element.php +++ /dev/null @@ -1,185 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - * - * @property-read string $name Header name. - * @property-read string $value_single The first header value. - */ -abstract class Horde_Mime_Headers_Element -implements IteratorAggregate -{ - /** - * Header name (UTF-8, although limited to US-ASCII subset by RFCs). - * - * @var string - */ - protected $_name; - - /** - * Header values. - * - * @var array - */ - protected $_values = array(); - - /** - * Constructor. - * - * @param string $name Header name. - * @param mixed $value Header value(s). - */ - public function __construct($name, $value) - { - $this->_name = trim($name); - if (strpos($this->_name, ' ') !== false) { - throw new InvalidArgumentException('Invalid header name'); - } - $this->setValue($value); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'name': - return $this->_name; - - case 'value_single': - return reset($this->_values); - } - } - - /** - * Set the value of the header. - * - * @param mixed $value Header value(s). - */ - final public function setValue($value) - { - $this->_setValue($value); - } - - /** - * TODO - */ - abstract protected function _setValue($value); - - /** - * Returns the encoded string value(s) needed when sending the header text - * to a RFC compliant mail submission server. - * - * @param array $opts Additional options: - * - charset: (string) Charset to encode to. - * DEFAULT: UTF-8 - * - * @return array An array of string values. - */ - final public function sendEncode(array $opts = array()) - { - return $this->_sendEncode(array_merge(array( - 'charset' => 'UTF-8' - ), $opts)); - } - - /** - * TODO - */ - protected function _sendEncode($opts) - { - return $this->_values; - } - - /** - * Perform sanity checking on a header value. - * - * @param string $data The header data. - * - * @return string The cleaned header data. - */ - protected function _sanityCheck($data) - { - $charset_test = array( - 'windows-1252', - Horde_Mime_Headers::$defaultCharset - ); - - if (!Horde_String::validUtf8($data)) { - /* Appears to be a PHP error with the internal String structure - * which prevents accurate manipulation of the string. Copying - * the data to a new variable fixes things. */ - $data = substr($data, 0); - - /* Assumption: broken charset in headers is generally either - * UTF-8 or ISO-8859-1/Windows-1252. Test these charsets - * first before using default charset. This may be a - * Western-centric approach, but it's better than nothing. */ - foreach ($charset_test as $charset) { - $tmp = Horde_String::convertCharset($data, $charset, 'UTF-8'); - if (Horde_String::validUtf8($tmp)) { - return $tmp; - } - } - } - - /* Ensure no null characters exist in header data. */ - if ($data === null) { - return ''; - } - return str_replace("\0", '', $data); - } - - /** - * If true, indicates the contents of the header is the default value. - * - * @since 2.8.0 - * - * @return boolean True if this header is the default value. - */ - public function isDefault() - { - return false; - } - - /* Static methods */ - - /** - * Return list of explicit header names handled by this driver. - * - * @return array Header list. - */ - public static function getHandles() - { - return array(); - } - - /* IteratorAggregate method */ - - /** - */ - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_values); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Element/Address.php b/lib/horde/framework/Horde/Mime/Headers/Element/Address.php deleted file mode 100644 index c51a21b452e..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Element/Address.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -interface Horde_Mime_Headers_Element_Address -{ - /** - * Return the address list representation(s) for this header. - * - * @param boolean $first If true, return only the first element rather - * than the entire list. - * - * @return mixed A Horde_Mail_Rfc822_List object (if $first is true) or - * an array of those objects. - */ - public function getAddressList($first = false); - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Element/Multiple.php b/lib/horde/framework/Horde/Mime/Headers/Element/Multiple.php deleted file mode 100644 index 4d93efa1a73..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Element/Multiple.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - * - * @property-read array $full_value List of full header values (strings). - * @property-read array $value List of header values (strings). - */ -class Horde_Mime_Headers_Element_Multiple -extends Horde_Mime_Headers_Element -{ - /** - */ - public function __get($name) - { - switch ($name) { - case 'full_value': - case 'value': - return $this->_values; - } - - return parent::__get($name); - } - - /** - */ - 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)); - } - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Element/Single.php b/lib/horde/framework/Horde/Mime/Headers/Element/Single.php deleted file mode 100644 index 004f646c390..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Element/Single.php +++ /dev/null @@ -1,91 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - * - * @property-read string $full_value Full header value. - * @property-read string $value Header value. - */ -class Horde_Mime_Headers_Element_Single -extends Horde_Mime_Headers_Element -{ - /** - */ - public function __get($name) - { - switch ($name) { - case 'full_value': - case 'value': - return reset($this->_values); - } - - return parent::__get($name); - } - - /** - */ - public function __toString() - { - return $this->value; - } - - /** - */ - 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)) - ); - } - - /** - */ - public static function getHandles() - { - return array( - // Mail: RFC 3798 - 'disposition-notification-options', - 'original-recipient', - // Lists: RFC 2369 - 'list-help', - 'list-unsubscribe', - 'list-subscribe', - 'list-owner', - 'list-post', - 'list-archive', - // Lists: RFC 2919 - 'list-id', - // Importance: See, e.g., RFC 4356 [2.1.3.3.1] - 'importance', - // OTHER: X-Priority - // See: http://kb.mozillazine.org/Emulate_Microsoft_email_clients - 'x-priority' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Extension/Mime.php b/lib/horde/framework/Horde/Mime/Headers/Extension/Mime.php deleted file mode 100644 index 9dd5fbdfc8e..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Extension/Mime.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.8.0 - */ -interface Horde_Mime_Headers_Extension_Mime -{ -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Identification.php b/lib/horde/framework/Horde/Mime/Headers/Identification.php deleted file mode 100644 index 241fb520c24..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Identification.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Headers_Identification -extends Horde_Mime_Headers_Element_Single -{ - /** - * Get the identification object for the header value. - * - * @return Horde_Mail_Rfc822_Identification Identification object. - */ - public function getIdentificationOb() - { - return new Horde_Mail_Rfc822_Identification($this->value); - } - - /** - */ - public static function getHandles() - { - return array( - // Mail: RFC 5322 - 'in-reply-to', - 'references' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/MessageId.php b/lib/horde/framework/Horde/Mime/Headers/MessageId.php deleted file mode 100644 index 06dce223b62..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/MessageId.php +++ /dev/null @@ -1,60 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Headers_MessageId -extends Horde_Mime_Headers_Identification -{ - /** - * Creates a Message-ID header conforming to RFC 2822 [3.6.4] and the - * standards outlined in 'draft-ietf-usefor-message-id-01.txt'. - * - * @param string $prefix A unique prefix to use. - * - * @return Horde_Mime_Headers_MessageId Message-ID header object. - */ - public static function create($prefix = 'Horde') - { - return new self( - null, - '<' . strval(new Horde_Support_Guid(array('prefix' => $prefix))) . '>' - ); - } - - /** - */ - public function __construct($name, $value) - { - parent::__construct('Message-ID', $value); - } - - /** - */ - public static function getHandles() - { - return array( - // Mail: RFC 5322 - 'message-id' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Mime.php b/lib/horde/framework/Horde/Mime/Headers/Mime.php deleted file mode 100644 index f8b6a157258..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Mime.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.8.0 - */ -class Horde_Mime_Headers_Mime -extends Horde_Mime_Headers_Element_Single -implements Horde_Mime_Headers_Extension_Mime -{ - /** - */ - public static function getHandles() - { - return array( - // MIME: RFC 1864 - 'content-md5', - // MIME: RFC 2110 - 'content-base', - // MIME: RFC 2424 - 'content-duration', - // MIME: RFC 2557 - 'content-location', - // MIME: RFC 2912 [3] - 'content-features', - // MIME: RFC 3297 - 'content-alternative' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/MimeVersion.php b/lib/horde/framework/Horde/Mime/Headers/MimeVersion.php deleted file mode 100644 index a2768539e32..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/MimeVersion.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Headers_MimeVersion -extends Horde_Mime_Headers_Element_Single -implements Horde_Mime_Headers_Extension_Mime -{ - /** - * Creates a MIME-Version header, conforming to the MIME specification as - * detailed in RFC 2045. - * - * @return Horde_Mime_Headers_MimeVersion MIME-Version header object. - */ - public static function create() - { - return new self(null, '1.0'); - } - - /** - */ - public function __construct($name, $value) - { - parent::__construct('MIME-Version', $value); - } - - /** - */ - public static function getHandles() - { - return array( - // MIME: RFC 2045 - 'mime-version' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Received.php b/lib/horde/framework/Horde/Mime/Headers/Received.php deleted file mode 100644 index d1ecd54f893..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Received.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Headers_Received -extends Horde_Mime_Headers_Element_Multiple -{ - /** - */ - public function __construct($name, $value) - { - parent::__construct('Received', $value); - } - - /** - */ - public static function getHandles() - { - return array( - // Mail: RFC 5322 - 'received' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/Subject.php b/lib/horde/framework/Horde/Mime/Headers/Subject.php deleted file mode 100644 index 79850fa7c3f..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/Subject.php +++ /dev/null @@ -1,51 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Headers_Subject -extends Horde_Mime_Headers_Element_Single -{ - /** - */ - public function __construct($name, $value) - { - parent::__construct('Subject', $value); - } - - /** - */ - protected function _sendEncode($opts) - { - return array(Horde_Mime::encode($this->value, $opts['charset'])); - } - - /** - */ - public static function getHandles() - { - return array( - // Mail: RFC 5322 - 'subject' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Headers/UserAgent.php b/lib/horde/framework/Horde/Mime/Headers/UserAgent.php deleted file mode 100644 index 9e9377fd7fb..00000000000 --- a/lib/horde/framework/Horde/Mime/Headers/UserAgent.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Headers_UserAgent -extends Horde_Mime_Headers_Element_Single -{ - /** - * Creates a default system User-Agent header. - * - * @return Horde_Mime_Headers_Single_UserAgent User-Agent header object. - */ - public static function create($prefix = 'Horde') - { - return new self( - null, - 'Horde Application Framework 5' - ); - } - - /** - */ - public function __construct($name, $value) - { - parent::__construct('User-Agent', $value); - } - - /** - */ - public static function getHandles() - { - return array( - // Mail: RFC 5322 - 'user-agent' - ); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Id.php b/lib/horde/framework/Horde/Mime/Id.php deleted file mode 100644 index 69b2129cf16..00000000000 --- a/lib/horde/framework/Horde/Mime/Id.php +++ /dev/null @@ -1,152 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Id -{ - /* Constants for idArithmetic() method. */ - const ID_DOWN = 1; - const ID_NEXT = 2; - const ID_PREV = 3; - const ID_UP = 4; - - /** - * MIME ID. - * - * @var string - */ - public $id; - - /** - * Constructor. - * - * @param string $id MIME ID. - */ - public function __construct($id) - { - $this->id = $id; - } - - /** - */ - public function __toString() - { - return $this->id; - } - - /** - * Performs MIME ID "arithmetic". - * - * @param string $action One of: - * - ID_DOWN: ID of child. Note: ID_DOWN will first traverse to "$id.0" - * if given an ID *NOT* of the form "$id.0". If given an ID of - * the form "$id.0", ID_DOWN will traverse to "$id.1". This - * behavior can be avoided if 'no_rfc822' option is set. - * - ID_NEXT: ID of next sibling. - * - ID_PREV: ID of previous sibling. - * - ID_UP: ID of parent. Note: ID_UP will first traverse to "$id.0" if - * given an ID *NOT* of the form "$id.0". If given an ID of the - * form "$id.0", ID_UP will traverse to "$id". This behavior can - * be avoided if 'no_rfc822' option is set. - * @param array $options Additional options: - * - count: (integer) How many levels to traverse. - * DEFAULT: 1 - * - no_rfc822: (boolean) Don't traverse RFC 822 sub-levels. - * DEFAULT: false - * - * @return mixed The resulting ID string, or null if that ID can not - * exist. - */ - public function idArithmetic($action, array $options = array()) - { - return $this->_idArithmetic($this->id, $action, array_merge(array( - 'count' => 1 - ), $options)); - } - - /** - * @see idArithmetic() - */ - protected function _idArithmetic($id, $action, $options) - { - $pos = strrpos($id, '.'); - $end = ($pos === false) ? $id : substr($id, $pos + 1); - - switch ($action) { - case self::ID_DOWN: - if ($end == '0') { - $id = ($pos === false) ? 1 : substr_replace($id, '1', $pos + 1); - } else { - $id .= empty($options['no_rfc822']) ? '.0' : '.1'; - } - break; - - case self::ID_NEXT: - ++$end; - $id = ($pos === false) ? $end : substr_replace($id, $end, $pos + 1); - break; - - case self::ID_PREV: - if (($end == '0') || - (empty($options['no_rfc822']) && ($end == '1'))) { - $id = null; - } elseif ($pos === false) { - $id = --$end; - } else { - $id = substr_replace($id, --$end, $pos + 1); - } - break; - - case self::ID_UP: - if ($pos === false) { - $id = ($end == '0') ? null : '0'; - } elseif (!empty($options['no_rfc822']) || ($end == '0')) { - $id = substr($id, 0, $pos); - } else { - $id = substr_replace($id, '0', $pos + 1); - } - break; - } - - return (!is_null($id) && --$options['count']) - ? $this->_idArithmetic($id, $action, $options) - : $id; - } - - /** - * Determines if a given MIME ID lives underneath a base ID. - * - * @param string $id The MIME ID to query. - * - * @return boolean Whether $id lives under the base ID ($this->id). - */ - public function isChild($id) - { - $base = (substr($this->id, -2) == '.0') - ? substr($this->id, 0, -1) - : rtrim($this->id, '.') . '.'; - - return ((($base == 0) && ($id != 0)) || - (strpos(strval($id), strval($base)) === 0)); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Magic.php b/lib/horde/framework/Horde/Mime/Magic.php deleted file mode 100644 index 6eb72afe4d4..00000000000 --- a/lib/horde/framework/Horde/Mime/Magic.php +++ /dev/null @@ -1,235 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @copyright 1999-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ -class Horde_Mime_Magic -{ - /** - * The MIME extension map. - * - * @var array - */ - protected static $_map = null; - - /** - * Returns a copy of the MIME extension map. - * - * @return array The MIME extension map. - */ - protected static function _getMimeExtensionMap() - { - if (is_null(self::$_map)) { - require __DIR__ . '/mime.mapping.php'; - self::$_map = $mime_extension_map; - } - - return self::$_map; - } - - /** - * Attempt to convert a file extension to a MIME type, based - * on the global Horde and application specific config files. - * - * If we cannot map the file extension to a specific type, then - * we fall back to a custom MIME handler 'x-extension/$ext', which - * can be used as a normal MIME type internally throughout Horde. - * - * @param string $ext The file extension to be mapped to a MIME type. - * - * @return string The MIME type of the file extension. - */ - public static function extToMime($ext) - { - if (empty($ext)) { - return 'application/octet-stream'; - } - - $ext = Horde_String::lower($ext); - $map = self::_getMimeExtensionMap(); - $pos = 0; - - while (!isset($map[$ext])) { - if (($pos = strpos($ext, '.')) === false) { - break; - } - $ext = substr($ext, $pos + 1); - } - - return isset($map[$ext]) - ? $map[$ext] - : 'x-extension/' . $ext; - } - - /** - * Attempt to convert a filename to a MIME type, based on the global Horde - * and application specific config files. - * - * @param string $filename The filename to be mapped to a MIME type. - * @param boolean $unknown How should unknown extensions be handled? If - * true, will return 'x-extension/*' types. If - * false, will return 'application/octet-stream'. - * - * @return string The MIME type of the filename. - */ - public static function filenameToMime($filename, $unknown = true) - { - $pos = strlen($filename) + 1; - $type = ''; - - $map = self::_getMimeExtensionMap(); - for ($i = 0; $i <= $map['__MAXPERIOD__']; ++$i) { - $npos = strrpos(substr($filename, 0, $pos - 1), '.'); - if ($npos === false) { - break; - } - $pos = $npos + 1; - } - - $type = ($pos === false) ? '' : self::extToMime(substr($filename, $pos)); - - return (empty($type) || (!$unknown && (strpos($type, 'x-extension') !== false))) - ? 'application/octet-stream' - : $type; - } - - /** - * Attempt to convert a MIME type to a file extension, based - * on the global Horde and application specific config files. - * - * If we cannot map the type to a file extension, we return false. - * - * @param string $type The MIME type to be mapped to a file extension. - * - * @return string The file extension of the MIME type. - */ - public static function mimeToExt($type) - { - if (empty($type)) { - return false; - } - - if (($key = array_search($type, self::_getMimeExtensionMap())) === false) { - list($major, $minor) = explode('/', $type); - if ($major == 'x-extension') { - return $minor; - } - if (strpos($minor, 'x-') === 0) { - return substr($minor, 2); - } - return false; - } - - return $key; - } - - /** - * Attempt to determine the MIME type of an unknown file. - * - * @param string $path The path to the file to analyze. - * @param string $magic_db Path to the mime magic database. - * @param array $opts Additional options: - * - nostrip: (boolean) Don't strip parameter information from MIME - * type string. - * DEFAULT: false - * - * @return mixed The MIME type of the file. Returns false if the file - * type can not be determined. - */ - public static function analyzeFile($path, $magic_db = null, - $opts = array()) - { - if (Horde_Util::extensionExists('fileinfo')) { - $res = empty($magic_db) - ? finfo_open(FILEINFO_MIME) - : finfo_open(FILEINFO_MIME, $magic_db); - - if ($res) { - $type = trim(finfo_file($res, $path)); - finfo_close($res); - - /* Remove any additional information. */ - if (empty($opts['nostrip'])) { - foreach (array(';', ',', '\\0') as $separator) { - if (($pos = strpos($type, $separator)) !== false) { - $type = rtrim(substr($type, 0, $pos)); - } - } - - if (preg_match('|^[a-z0-9]+/[.-a-z0-9]+$|i', $type)) { - return $type; - } - } else { - return $type; - } - } - } - - return false; - } - - /** - * Attempt to determine the MIME type of an unknown byte stream. - * - * @param string $data The file data to analyze. - * @param string $magic_db Path to the mime magic database. - * @param array $opts Additional options: - * - nostrip: (boolean) Don't strip parameter information from MIME - * type string. - * DEFAULT: false - * - * @return mixed The MIME type of the file. Returns false if the file - * type can not be determined. - */ - public static function analyzeData($data, $magic_db = null, - $opts = array()) - { - /* If the PHP Mimetype extension is available, use that. */ - if (Horde_Util::extensionExists('fileinfo')) { - $res = empty($magic_db) - ? @finfo_open(FILEINFO_MIME) - : @finfo_open(FILEINFO_MIME, $magic_db); - - if (!$res) { - return false; - } - - $type = trim(finfo_buffer($res, $data)); - finfo_close($res); - - /* Remove any additional information. */ - if (empty($opts['nostrip'])) { - if (($pos = strpos($type, ';')) !== false) { - $type = rtrim(substr($type, 0, $pos)); - } - - if (($pos = strpos($type, ',')) !== false) { - $type = rtrim(substr($type, 0, $pos)); - } - } - - return $type; - } - - return false; - } - -} diff --git a/lib/horde/framework/Horde/Mime/Mail.php b/lib/horde/framework/Horde/Mime/Mail.php deleted file mode 100644 index cbec8ea2274..00000000000 --- a/lib/horde/framework/Horde/Mime/Mail.php +++ /dev/null @@ -1,524 +0,0 @@ - - * @category Horde - * @copyright 2007-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ -class Horde_Mime_Mail -{ - /** - * The message headers. - * - * @var Horde_Mime_Headers - */ - protected $_headers; - - /** - * The base MIME part. - * - * @var Horde_Mime_Part - */ - protected $_base; - - /** - * The main body part. - * - * @var Horde_Mime_Part - */ - protected $_body; - - /** - * The main HTML body part. - * - * @var Horde_Mime_Part - */ - protected $_htmlBody; - - /** - * The message recipients. - * - * @var Horde_Mail_Rfc822_List - */ - protected $_recipients; - - /** - * Bcc recipients. - * - * @var string - */ - protected $_bcc; - - /** - * All MIME parts except the main body part. - * - * @var array - */ - protected $_parts = array(); - - /** - * The Mail driver name. - * - * @link http://pear.php.net/Mail - * @var string - */ - protected $_mailer_driver = 'smtp'; - - /** - * The charset to use for the message. - * - * @var string - */ - protected $_charset = 'UTF-8'; - - /** - * The Mail driver parameters. - * - * @link http://pear.php.net/Mail - * @var array - */ - protected $_mailer_params = array(); - - /** - * Constructor. - * - * @param array $params A hash with basic message information. 'charset' - * is the character set of the message. 'body' is - * the message body. All other parameters are - * assumed to be message headers. - * - * @throws Horde_Mime_Exception - */ - public function __construct($params = array()) - { - /* Set SERVER_NAME. */ - if (!isset($_SERVER['SERVER_NAME'])) { - $_SERVER['SERVER_NAME'] = php_uname('n'); - } - - $this->_headers = new Horde_Mime_Headers(); - - if (isset($params['charset'])) { - $this->_charset = $params['charset']; - unset($params['charset']); - } - - if (isset($params['body'])) { - $this->setBody($params['body'], $this->_charset); - unset($params['body']); - } - - $this->addHeaders($params); - - $this->clearRecipients(); - } - - /** - * Adds several message headers at once. - * - * @param array $header Hash with header names as keys and header - * contents as values. - * - * @throws Horde_Mime_Exception - */ - public function addHeaders($headers = array()) - { - foreach ($headers as $header => $value) { - $this->addHeader($header, $value); - } - } - - /** - * Adds a message header. - * - * @param string $header The header name. - * @param string $value The header value. - * @param boolean $overwrite If true, an existing header of the same name - * is being overwritten; if false, multiple - * headers are added; if null, the correct - * behaviour is automatically chosen depending - * on the header name. - * - * @throws Horde_Mime_Exception - */ - public function addHeader($header, $value, $overwrite = null) - { - $lc_header = Horde_String::lower($header); - - if (is_null($overwrite) && - in_array($lc_header, $this->_headers->singleFields(true))) { - $overwrite = true; - } - - if ($overwrite) { - $this->_headers->removeHeader($header); - } - - if ($lc_header === 'bcc') { - $this->_bcc = $value; - } else { - $this->_headers->addHeader($header, $value); - } - } - - /** - * Add a Horde_Mime_Headers_Element object to the current header list. - * - * @since 2.5.0 - * - * @param Horde_Mime_Headers_Element $ob Header object to add. - * - * @throws InvalidArgumentException - */ - public function addHeaderOb(Horde_Mime_Headers_Element $ob) - { - $this->_headers->addHeaderOb($ob, true); - } - - /** - * Removes a message header. - * - * @param string $header The header name. - */ - public function removeHeader($header) - { - if (Horde_String::lower($header) === 'bcc') { - unset($this->_bcc); - } else { - $this->_headers->removeHeader($header); - } - } - - /** - * Sets the message body text. - * - * @param string $body The message content. - * @param string $charset The character set of the message. - * @param boolean|integer $wrap If true, wrap the message at column 76; - * If an integer wrap the message at that - * column. Don't use wrapping if sending - * flowed messages. - */ - public function setBody($body, $charset = null, $wrap = false) - { - if (!$charset) { - $charset = $this->_charset; - } - $body = Horde_String::convertCharset($body, 'UTF-8', $charset); - if ($wrap) { - $body = Horde_String::wrap($body, $wrap === true ? 76 : $wrap); - } - $this->_body = new Horde_Mime_Part(); - $this->_body->setType('text/plain'); - $this->_body->setCharset($charset); - $this->_body->setContents($body); - $this->_base = null; - } - - /** - * Sets the HTML message body text. - * - * @param string $body The message content. - * @param string $charset The character set of the message. - * @param boolean $alternative If true, a multipart/alternative message is - * created and the text/plain part is - * generated automatically. If false, a - * text/html message is generated. - */ - public function setHtmlBody($body, $charset = null, $alternative = true) - { - if (!$charset) { - $charset = $this->_charset; - } - $this->_htmlBody = new Horde_Mime_Part(); - $this->_htmlBody->setType('text/html'); - $this->_htmlBody->setCharset($charset); - $this->_htmlBody->setContents($body); - if ($alternative) { - $this->setBody(Horde_Text_Filter::filter($body, 'Html2text', array('charset' => $charset, 'wrap' => false)), $charset); - } - $this->_base = null; - } - - /** - * Adds a message part. - * - * @param string $mime_type The content type of the part. - * @param string $content The content of the part. - * @param string $charset The character set of the part. - * @param string $disposition The content disposition of the part. - * - * @return integer The part number. - */ - public function addPart($mime_type, $content, $charset = 'us-ascii', - $disposition = null) - { - $part = new Horde_Mime_Part(); - $part->setType($mime_type); - $part->setCharset($charset); - $part->setDisposition($disposition); - $part->setContents($content); - return $this->addMimePart($part); - } - - /** - * Adds a MIME message part. - * - * @param Horde_Mime_Part $part A Horde_Mime_Part object. - * - * @return integer The part number. - */ - public function addMimePart($part) - { - $this->_parts[] = $part; - return count($this->_parts) - 1; - } - - /** - * Sets the base MIME part. - * - * If the base part is set, any text bodies will be ignored when building - * the message. - * - * @param Horde_Mime_Part $part A Horde_Mime_Part object. - */ - public function setBasePart($part) - { - $this->_base = $part; - } - - /** - * Adds an attachment. - * - * @param string $file The path to the file. - * @param string $name The file name to use for the attachment. - * @param string $type The content type of the file. - * @param string $charset The character set of the part (only relevant for - * text parts. - * - * @return integer The part number. - */ - public function addAttachment($file, $name = null, $type = null, - $charset = 'us-ascii') - { - if (empty($name)) { - $name = basename($file); - } - - if (empty($type)) { - $type = Horde_Mime_Magic::filenameToMime($file, false); - } - - $num = $this->addPart($type, file_get_contents($file), $charset, 'attachment'); - $this->_parts[$num]->setName($name); - return $num; - } - - /** - * Removes a message part. - * - * @param integer $part The part number. - */ - public function removePart($part) - { - if (isset($this->_parts[$part])) { - unset($this->_parts[$part]); - } - } - - /** - * Removes all (additional) message parts but leaves the body parts - * untouched. - */ - public function clearParts() - { - $this->_parts = array(); - } - - /** - * Adds message recipients. - * - * Recipients specified by To:, Cc:, or Bcc: headers are added - * automatically. - * - * @param string|array List of recipients, either as a comma separated - * list or as an array of email addresses. - * - * @throws Horde_Mime_Exception - */ - public function addRecipients($recipients) - { - $this->_recipients->add($recipients); - } - - /** - * Removes message recipients. - * - * @param string|array List of recipients, either as a comma separated - * list or as an array of email addresses. - * - * @throws Horde_Mime_Exception - */ - public function removeRecipients($recipients) - { - $this->_recipients->remove($recipients); - } - - /** - * Removes all message recipients. - */ - public function clearRecipients() - { - $this->_recipients = new Horde_Mail_Rfc822_List(); - } - - /** - * Sends this message. - * - * @param Horde_Mail_Transport $mailer A Horde_Mail_Transport object. - * @param boolean $resend If true, the message id and date are re-used; - * If false, they will be updated. - * @param boolean $flowed Send message in flowed text format. - * - * @throws Horde_Mime_Exception - */ - public function send($mailer, $resend = false, $flowed = true) - { - /* Add mandatory headers if missing. */ - if (!$resend || !isset($this->_headers['Message-ID'])) { - $this->_headers->addHeaderOb( - Horde_Mime_Headers_MessageId::create() - ); - } - if (!isset($this->_headers['User-Agent'])) { - $this->_headers->addHeaderOb( - Horde_Mime_Headers_UserAgent::create() - ); - } - if (!$resend || !isset($this->_headers['Date'])) { - $this->_headers->addHeaderOb(Horde_Mime_Headers_Date::create()); - } - - if (isset($this->_base)) { - $basepart = $this->_base; - } else { - /* Send in flowed format. */ - if ($flowed && !empty($this->_body)) { - $flowed = new Horde_Text_Flowed($this->_body->getContents(), $this->_body->getCharset()); - $flowed->setDelSp(true); - $this->_body->setContentTypeParameter('format', 'flowed'); - $this->_body->setContentTypeParameter('DelSp', 'Yes'); - $this->_body->setContents($flowed->toFlowed()); - } - - /* Build mime message. */ - $body = new Horde_Mime_Part(); - if (!empty($this->_body) && !empty($this->_htmlBody)) { - $body->setType('multipart/alternative'); - $this->_body->setDescription(Horde_Mime_Translation::t("Plaintext Version of Message")); - $body[] = $this->_body; - $this->_htmlBody->setDescription(Horde_Mime_Translation::t("HTML Version of Message")); - $body[] = $this->_htmlBody; - } elseif (!empty($this->_htmlBody)) { - $body = $this->_htmlBody; - } elseif (!empty($this->_body)) { - $body = $this->_body; - } - if (count($this->_parts)) { - $basepart = new Horde_Mime_Part(); - $basepart->setType('multipart/mixed'); - $basepart->isBasePart(true); - if ($body) { - $basepart[] = $body; - } - foreach ($this->_parts as $mime_part) { - $basepart[] = $mime_part; - } - } else { - $basepart = $body; - $basepart->isBasePart(true); - } - } - $basepart->setHeaderCharset($this->_charset); - - /* Build recipients. */ - $recipients = clone $this->_recipients; - foreach (array('to', 'cc') as $header) { - if ($h = $this->_headers[$header]) { - $recipients->add($h->getAddressList()); - } - } - if ($this->_bcc) { - $recipients->add($this->_bcc); - } - - /* Trick Horde_Mime_Part into re-generating the message headers. */ - $this->_headers->removeHeader('MIME-Version'); - - /* Send message. */ - $recipients->unique(); - $basepart->send($recipients->writeAddress(), $this->_headers, $mailer); - - /* Remember the basepart */ - $this->_base = $basepart; - } - - /** - * Get the raw email data sent by this object. - * - * @param boolean $stream If true, return a stream resource, otherwise - * a string is returned. - * - * @return resource|string The raw email data. - * @since 2.4.0 - */ - public function getRaw($stream = true) - { - if ($stream) { - $hdr = new Horde_Stream(); - $hdr->add($this->_headers->toString(), true); - return Horde_Stream_Wrapper_Combine::getStream( - array($hdr->stream, - $this->getBasePart()->toString( - array('stream' => true, 'encode' => Horde_Mime_Part::ENCODE_7BIT | Horde_Mime_Part::ENCODE_8BIT | Horde_Mime_Part::ENCODE_BINARY)) - ) - ); - } - - return $this->_headers->toString() . $this->getBasePart()->toString(); - } - - /** - * Return the base MIME part. - * - * @return Horde_Mime_Part - */ - public function getBasePart() - { - if (empty($this->_base)) { - throw new Horde_Mail_Exception('No base part set.'); - } - - return $this->_base; - } - -} diff --git a/lib/horde/framework/Horde/Mime/Mdn.php b/lib/horde/framework/Horde/Mime/Mdn.php deleted file mode 100644 index 43ef502ac3b..00000000000 --- a/lib/horde/framework/Horde/Mime/Mdn.php +++ /dev/null @@ -1,276 +0,0 @@ - - * @category Horde - * @copyright 2004-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ -class Horde_Mime_Mdn -{ - /* RFC 3798 header for requesting a MDN. */ - const MDN_HEADER = 'Disposition-Notification-To'; - - /** - * The Horde_Mime_Headers object. - * - * @var Horde_Mime_Headers - */ - protected $_headers; - - /** - * The text of the original message. - * - * @var string - */ - protected $_msgtext = false; - - /** - * Constructor. - * - * @param Horde_Mime_Headers $mime_headers A headers object. - */ - public function __construct(Horde_Mime_Headers $headers) - { - $this->_headers = $headers; - } - - /** - * Returns the address(es) to return the MDN to. - * - * @return string The address(es) to send the MDN to. Returns null if no - * MDN is requested. - */ - public function getMdnReturnAddr() - { - /* RFC 3798 [2.1] requires the Disposition-Notification-To header - * for an MDN to be created. */ - return ($hdr = $this->_headers[self::MDN_HEADER]) - ? strval($hdr) - : null; - } - - /** - * Is user input required to send the MDN? - * Explicit confirmation is needed in some cases to prevent mail loops - * and the use of MDNs for mail bombing. - * - * @return boolean Is explicit user input required to send the MDN? - */ - public function userConfirmationNeeded() - { - $return_path = $this->_headers['Return-Path']; - - /* RFC 3798 [2.1]: Explicit confirmation is needed if there is no - * Return-Path in the header. Also, "if the message contains more - * than one Return-Path header, the implementation may [] treat the - * situation as a failure of the comparison." */ - if (!$return_path || (count($return_path->value) > 1)) { - return true; - } - - /* RFC 3798 [2.1]: Explicit confirmation is needed if there is more - * than one distinct address in the Disposition-Notification-To - * header. */ - $addr_ob = ($hdr = $this->_headers[self::MDN_HEADER]) - ? $hdr->getAddressList(true) - : array(); - - switch (count($addr_ob)) { - case 0: - return false; - - case 1: - // No-op - break; - - default: - return true; - } - - /* RFC 3798 [2.1] states that "MDNs SHOULD NOT be sent automatically - * if the address in the Disposition-Notification-To header differs - * from the address in the Return-Path header." This comparison is - * case-sensitive for the mailbox part and case-insensitive for the - * host part. */ - $ret_ob = new Horde_Mail_Rfc822_Address($return_path->value); - return (!$ret_ob->valid || !$addr_ob->match($ret_ob)); - } - - /** - * When generating the MDN, should we return the enitre text of the - * original message? The default is no - we only return the headers of - * the original message. If the text is passed in via this method, we - * will return the entire message. - * - * @param string $text The text of the original message. - */ - public function originalMessageText($text) - { - $this->_msgtext = $text; - } - - /** - * Generate the MDN according to the specifications listed in RFC - * 3798 [3]. - * - * @param boolean $action Was this MDN type a result of a manual - * action on part of the user? - * @param boolean $sending Was this MDN sent as a result of a manual - * action on part of the user? - * @param string $type The type of action performed by the user. - * Per RFC 3798 [3.2.6.2] the following types are - * valid: - * - deleted - * - displayed - * @param string $name The name of the local server. - * @param Horde_Mail_Transport $mailer Mail transport object. - * @param array $opts Additional options: - * - charset: (string) Default charset. - * DEFAULT: NONE - * - from_addr: (string) From address. - * DEFAULT: NONE - * @param array $mod The list of modifications. Per RFC 3798 - * [3.2.6.3] the following modifications are - * valid: - * - error - * @param array $err If $mod is 'error', the additional - * information to provide. Key is the type of - * modification, value is the text. - */ - public function generate($action, $sending, $type, $name, $mailer, - array $opts = array(), array $mod = array(), - array $err = array()) - { - $opts = array_merge(array( - 'charset' => null, - 'from_addr' => null - ), $opts); - - if (!($hdr = $this->_headers[self::MDN_HEADER])) { - throw new RuntimeException( - 'Need at least one address to send MDN to.' - ); - } - - $to = $hdr->getAddressList(true); - $ua = Horde_Mime_Headers_UserAgent::create(); - - if ($orig_recip = $this->_headers['Original-Recipient']) { - $orig_recip = $orig_recip->value_single; - } - - /* Set up the mail headers. */ - $msg_headers = new Horde_Mime_Headers(); - $msg_headers->addHeaderOb(Horde_Mime_Headers_MessageId::create()); - $msg_headers->addHeaderOb($ua); - /* RFC 3834 [5.2] */ - $msg_headers->addHeader('Auto-Submitted', 'auto-replied'); - $msg_headers->addHeaderOb(Horde_Mime_Headers_Date::create()); - if ($opts['from_addr']) { - $msg_headers->addHeader('From', $opts['from_addr']); - } - $msg_headers->addHeader('To', $to); - $msg_headers->addHeader('Subject', Horde_Mime_Translation::t("Disposition Notification")); - - /* MDNs are a subtype of 'multipart/report'. */ - $msg = new Horde_Mime_Part(); - $msg->setType('multipart/report'); - $msg->setContentTypeParameter('report-type', 'disposition-notification'); - - /* The first part is a human readable message. */ - $part_one = new Horde_Mime_Part(); - $part_one->setType('text/plain'); - $part_one->setCharset($opts['charset']); - if ($type == 'displayed') { - $contents = sprintf( - Horde_Mime_Translation::t("The message sent on %s to %s with subject \"%s\" has been displayed.\n\nThis is no guarantee that the message has been read or understood."), - $this->_headers['Date'], - $this->_headers['To'], - $this->_headers['Subject'] - ); - $flowed = new Horde_Text_Flowed($contents, $opts['charset']); - $flowed->setDelSp(true); - $part_one->setContentTypeParameter('format', 'flowed'); - $part_one->setContentTypeParameter('DelSp', 'Yes'); - $part_one->setContents($flowed->toFlowed()); - } - // TODO: Messages for other notification types. - $msg[] = $part_one; - - /* The second part is a machine-parseable description. */ - $part_two = new Horde_Mime_Part(); - $part_two->setType('message/disposition-notification'); - - $part_two_h = new Horde_Mime_Headers(); - $part_two_h->addHeader('Reporting-UA', $name . '; ' . $ua); - if (!empty($orig_recip)) { - $part_two_h->addHeader('Original-Recipient', 'rfc822;' . $orig_recip); - } - if ($opts['from_addr']) { - $part_two_h->addHeader('Final-Recipient', 'rfc822;' . $opts['from_addr']); - } - - if ($msg_id = $this->_headers['Message-ID']) { - $part_two_h->addHeader('Original-Message-ID', strval($msg_id)); - } - - /* Create the Disposition field now (RFC 3798 [3.2.6]). */ - $dispo = (($action) ? 'manual-action' : 'automatic-action') . - '/' . - (($sending) ? 'MDN-sent-manually' : 'MDN-sent-automatically') . - '; ' . - $type; - if (!empty($mod)) { - $dispo .= '/' . implode(', ', $mod); - } - $part_two_h->addHeader('Disposition', $dispo); - - if (in_array('error', $mod) && isset($err['error'])) { - $part_two_h->addHeader('Error', $err['error']); - } - - $part_two->setContents(trim($part_two_h->toString()) . "\n"); - $msg[] = $part_two; - - /* The third part is the text of the original message. RFC 3798 [3] - * allows us to return only a portion of the entire message - this - * is left up to the user. */ - $part_three = new Horde_Mime_Part(); - $part_three->setType('message/rfc822'); - $part_three_text = array(trim($this->_headers->toString()) . "\n"); - if (!empty($this->_msgtext)) { - $part_three_text[] = "\n" . $this->_msgtext; - } - $part_three->setContents($part_three_text); - $msg[] = $part_three; - - return $msg->send($to, $msg_headers, $mailer); - } - - /** - * Add a MDN (read receipt) request header. - * - * @param mixed $to The address(es) the receipt should be mailed to. - */ - public function addMdnRequestHeaders($to) - { - /* This is the RFC 3798 way of requesting a receipt. */ - $this->_headers->addHeader(self::MDN_HEADER, $to); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Part.php b/lib/horde/framework/Horde/Mime/Part.php deleted file mode 100644 index a20760a4ff4..00000000000 --- a/lib/horde/framework/Horde/Mime/Part.php +++ /dev/null @@ -1,2548 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @copyright 1999-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ -class Horde_Mime_Part -implements ArrayAccess, Countable, RecursiveIterator, Serializable -{ - /* Serialized version. */ - const VERSION = 2; - - /* The character(s) used internally for EOLs. */ - const EOL = "\n"; - - /* The character string designated by RFC 2045 to designate EOLs in MIME - * messages. */ - const RFC_EOL = "\r\n"; - - /* The default encoding. */ - const DEFAULT_ENCODING = 'binary'; - - /* Constants indicating the valid transfer encoding allowed. */ - const ENCODE_7BIT = 1; - const ENCODE_8BIT = 2; - const ENCODE_BINARY = 4; - - /* MIME nesting limit. */ - const NESTING_LIMIT = 100; - - /* Status mask value: Need to reindex the current part. */ - const STATUS_REINDEX = 1; - /* Status mask value: This is the base MIME part. */ - const STATUS_BASEPART = 2; - - /** - * The default charset to use when parsing text parts with no charset - * information. - * - * @todo Make this a non-static property or pass as parameter to static - * methods in Horde 6. - * - * @var string - */ - public static $defaultCharset = 'us-ascii'; - - /** - * The memory limit for use with the PHP temp stream. - * - * @var integer - */ - public static $memoryLimit = 2097152; - - /** - * Parent object. Value only accurate when iterating. - * - * @since 2.8.0 - * - * @var Horde_Mime_Part - */ - public $parent = null; - - /** - * Default value for this Part's size. - * - * @var integer - */ - protected $_bytes; - - /** - * The body of the part. Always stored in binary format. - * - * @var resource - */ - protected $_contents; - - /** - * The sequence to use as EOL for this part. - * - * The default is currently to output the EOL sequence internally as - * just "\n" instead of the canonical "\r\n" required in RFC 822 & 2045. - * To be RFC complaint, the full EOL combination should be used - * when sending a message. - * - * @var string - */ - protected $_eol = self::EOL; - - /** - * The MIME headers for this part. - * - * @var Horde_Mime_Headers - */ - protected $_headers; - - /** - * The charset to output the headers in. - * - * @var string - */ - protected $_hdrCharset = null; - - /** - * Metadata. - * - * @var array - */ - protected $_metadata = array(); - - /** - * The MIME ID of this part. - * - * @var string - */ - protected $_mimeid = null; - - /** - * The subparts of this part. - * - * @var array - */ - protected $_parts = array(); - - /** - * Status mask for this part. - * - * @var integer - */ - protected $_status = 0; - - /** - * Temporary array. - * - * @var array - */ - protected $_temp = array(); - - /** - * The desired transfer encoding of this part. - * - * @var string - */ - protected $_transferEncoding = self::DEFAULT_ENCODING; - - /** - * Flag to detect if a message failed to send at least once. - * - * @var boolean - */ - protected $_failed = false; - - /** - * Constructor. - */ - public function __construct() - { - $this->_headers = new Horde_Mime_Headers(); - - /* Mandatory MIME headers. */ - $this->_headers->addHeaderOb( - new Horde_Mime_Headers_ContentParam_ContentDisposition(null, '') - ); - - $ct = Horde_Mime_Headers_ContentParam_ContentType::create(); - $ct['charset'] = self::$defaultCharset; - $this->_headers->addHeaderOb($ct); - } - - /** - * Function to run on clone. - */ - public function __clone() - { - foreach ($this->_parts as $k => $v) { - $this->_parts[$k] = clone $v; - } - - $this->_headers = clone $this->_headers; - - if (!empty($this->_contents)) { - $this->_contents = $this->_writeStream($this->_contents); - } - } - - /** - * Set the content-disposition of this part. - * - * @param string $disposition The content-disposition to set ('inline', - * 'attachment', or an empty value). - */ - public function setDisposition($disposition = null) - { - $this->_headers['content-disposition']->setContentParamValue( - strval($disposition) - ); - } - - /** - * Get the content-disposition of this part. - * - * @return string The part's content-disposition. An empty string means - * no desired disposition has been set for this part. - */ - public function getDisposition() - { - return $this->_headers['content-disposition']->value; - } - - /** - * Add a disposition parameter to this part. - * - * @param string $label The disposition parameter label. - * @param string $data The disposition parameter data. If null, removes - * the parameter (@since 2.8.0). - */ - public function setDispositionParameter($label, $data) - { - $cd = $this->_headers['content-disposition']; - - if (is_null($data)) { - unset($cd[$label]); - } elseif (strlen($data)) { - $cd[$label] = $data; - - if (strcasecmp($label, 'size') === 0) { - // RFC 2183 [2.7] - size parameter - $this->_bytes = $cd[$label]; - } elseif ((strcasecmp($label, 'filename') === 0) && - !strlen($cd->value)) { - /* Set part to attachment if not already explicitly set to - * 'inline'. */ - $cd->setContentParamValue('attachment'); - } - } - } - - /** - * Get a disposition parameter from this part. - * - * @param string $label The disposition parameter label. - * - * @return string The data requested. - * Returns null if $label is not set. - */ - public function getDispositionParameter($label) - { - $cd = $this->_headers['content-disposition']; - return $cd[$label]; - } - - /** - * Get all parameters from the Content-Disposition header. - * - * @return array An array of all the parameters - * Returns the empty array if no parameters set. - */ - public function getAllDispositionParameters() - { - return $this->_headers['content-disposition']->params; - } - - /** - * Set the name of this part. - * - * @param string $name The name to set. - */ - public function setName($name) - { - $this->setDispositionParameter('filename', $name); - $this->setContentTypeParameter('name', $name); - } - - /** - * Get the name of this part. - * - * @param boolean $default If the name parameter doesn't exist, should we - * use the default name from the description - * parameter? - * - * @return string The name of the part. - */ - public function getName($default = false) - { - if (!($name = $this->getDispositionParameter('filename')) && - !($name = $this->getContentTypeParameter('name')) && - $default) { - $name = preg_replace('|\W|', '_', $this->getDescription(false)); - } - - return $name; - } - - /** - * Set the body contents of this part. - * - * @param mixed $contents The part body. Either a string or a stream - * resource, or an array containing both. - * @param array $options Additional options: - * - encoding: (string) The encoding of $contents. - * DEFAULT: Current transfer encoding value. - * - usestream: (boolean) If $contents is a stream, should we directly - * use that stream? - * DEFAULT: $contents copied to a new stream. - */ - public function setContents($contents, $options = array()) - { - if (is_resource($contents) && ($contents === $this->_contents)) { - return; - } - - if (empty($options['encoding'])) { - $options['encoding'] = $this->_transferEncoding; - } - - $fp = (empty($options['usestream']) || !is_resource($contents)) - ? $this->_writeStream($contents) - : $contents; - - /* Properly close the existing stream. */ - $this->clearContents(); - - $this->setTransferEncoding($options['encoding']); - $this->_contents = $this->_transferDecode($fp, $options['encoding']); - } - - /** - * Add to the body contents of this part. - * - * @param mixed $contents The part body. Either a string or a stream - * resource, or an array containing both. - * - encoding: (string) The encoding of $contents. - * DEFAULT: Current transfer encoding value. - * - usestream: (boolean) If $contents is a stream, should we directly - * use that stream? - * DEFAULT: $contents copied to a new stream. - */ - public function appendContents($contents, $options = array()) - { - if (empty($this->_contents)) { - $this->setContents($contents, $options); - } else { - $fp = (empty($options['usestream']) || !is_resource($contents)) - ? $this->_writeStream($contents) - : $contents; - - $this->_writeStream((empty($options['encoding']) || ($options['encoding'] == $this->_transferEncoding)) ? $fp : $this->_transferDecode($fp, $options['encoding']), array('fp' => $this->_contents)); - unset($this->_temp['sendTransferEncoding']); - } - } - - /** - * Clears the body contents of this part. - */ - public function clearContents() - { - if (!empty($this->_contents)) { - fclose($this->_contents); - $this->_contents = null; - unset($this->_temp['sendTransferEncoding']); - } - } - - /** - * Return the body of the part. - * - * @param array $options Additional options: - * - canonical: (boolean) Returns the contents in strict RFC 822 & - * 2045 output - namely, all newlines end with the - * canonical sequence. - * DEFAULT: No - * - stream: (boolean) Return the body as a stream resource. - * DEFAULT: No - * - * @return mixed The body text (string) of the part, null if there is no - * contents, and a stream resource if 'stream' is true. - */ - public function getContents($options = array()) - { - return empty($options['canonical']) - ? (empty($options['stream']) ? $this->_readStream($this->_contents) : $this->_contents) - : $this->replaceEOL($this->_contents, self::RFC_EOL, !empty($options['stream'])); - } - - /** - * Decodes the contents of the part to binary encoding. - * - * @param resource $fp A stream containing the data to decode. - * @param string $encoding The original file encoding. - * - * @return resource A new file resource with the decoded data. - */ - protected function _transferDecode($fp, $encoding) - { - /* If the contents are empty, return now. */ - fseek($fp, 0, SEEK_END); - if (ftell($fp)) { - switch ($encoding) { - case 'base64': - try { - return $this->_writeStream($fp, array( - 'error' => true, - 'filter' => array( - 'convert.base64-decode' => array() - ) - )); - } catch (ErrorException $e) {} - - rewind($fp); - return $this->_writeStream(base64_decode(stream_get_contents($fp))); - - case 'quoted-printable': - try { - return $this->_writeStream($fp, array( - 'error' => true, - 'filter' => array( - 'convert.quoted-printable-decode' => array() - ) - )); - } catch (ErrorException $e) {} - - // Workaround for Horde Bug #8747 - rewind($fp); - return $this->_writeStream(quoted_printable_decode(stream_get_contents($fp))); - - case 'uuencode': - case 'x-uuencode': - case 'x-uue': - /* Support for uuencoded encoding - although not required by - * RFCs, some mailers may still encode this way. */ - $res = Horde_Mime::uudecode($this->_readStream($fp)); - return $this->_writeStream($res[0]['data']); - } - } - - return $fp; - } - - /** - * Encodes the contents of the part as necessary for transport. - * - * @param resource $fp A stream containing the data to encode. - * @param string $encoding The encoding to use. - * - * @return resource A new file resource with the encoded data. - */ - protected function _transferEncode($fp, $encoding) - { - $this->_temp['transferEncodeClose'] = true; - - switch ($encoding) { - case 'base64': - /* Base64 Encoding: See RFC 2045, section 6.8 */ - return $this->_writeStream($fp, array( - 'filter' => array( - 'convert.base64-encode' => array( - 'line-break-chars' => $this->getEOL(), - 'line-length' => 76 - ) - ) - )); - - case 'quoted-printable': - // PHP Bug 65776 - Must normalize the EOL characters. - stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol'); - $stream = new Horde_Stream_Existing(array( - 'stream' => $fp - )); - $stream->stream = $this->_writeStream($stream->stream, array( - 'filter' => array( - 'horde_eol' => array('eol' => $stream->getEOL() - ) - ))); - - /* Quoted-Printable Encoding: See RFC 2045, section 6.7 */ - return $this->_writeStream($fp, array( - 'filter' => array( - 'convert.quoted-printable-encode' => array_filter(array( - 'line-break-chars' => $stream->getEOL(), - 'line-length' => 76 - )) - ) - )); - - default: - $this->_temp['transferEncodeClose'] = false; - return $fp; - } - } - - /** - * Set the MIME type of this part. - * - * @param string $type The MIME type to set (ex.: text/plain). - */ - public function setType($type) - { - /* RFC 2045: Any entity with unrecognized encoding must be treated - * as if it has a Content-Type of "application/octet-stream" - * regardless of what the Content-Type field actually says. */ - if (!is_null($this->_transferEncoding)) { - $this->_headers['content-type']->setContentParamValue($type); - } - } - - /** - * Get the full MIME Content-Type of this part. - * - * @param boolean $charset Append character set information to the end - * of the content type if this is a text/* part? - *` - * @return string The MIME type of this part. - */ - public function getType($charset = false) - { - $ct = $this->_headers['content-type']; - - return $charset - ? $ct->type_charset - : $ct->value; - } - - /** - * If the subtype of a MIME part is unrecognized by an application, the - * default type should be used instead (See RFC 2046). This method - * returns the default subtype for a particular primary MIME type. - * - * @return string The default MIME type of this part (ex.: text/plain). - */ - public function getDefaultType() - { - switch ($this->getPrimaryType()) { - case 'text': - /* RFC 2046 (4.1.4): text parts default to text/plain. */ - return 'text/plain'; - - case 'multipart': - /* RFC 2046 (5.1.3): multipart parts default to multipart/mixed. */ - return 'multipart/mixed'; - - default: - /* RFC 2046 (4.2, 4.3, 4.4, 4.5.3, 5.2.4): all others default to - application/octet-stream. */ - return 'application/octet-stream'; - } - } - - /** - * Get the primary type of this part. - * - * @return string The primary MIME type of this part. - */ - public function getPrimaryType() - { - return $this->_headers['content-type']->ptype; - } - - /** - * Get the subtype of this part. - * - * @return string The MIME subtype of this part. - */ - public function getSubType() - { - return $this->_headers['content-type']->stype; - } - - /** - * Set the character set of this part. - * - * @param string $charset The character set of this part. - */ - public function setCharset($charset) - { - $this->setContentTypeParameter('charset', $charset); - } - - /** - * Get the character set to use for this part. - * - * @return string The character set of this part (lowercase). Returns - * null if there is no character set. - */ - public function getCharset() - { - return $this->getContentTypeParameter('charset') - ?: (($this->getPrimaryType() === 'text') ? 'us-ascii' : null); - } - - /** - * Set the character set to use when outputting MIME headers. - * - * @param string $charset The character set. - */ - public function setHeaderCharset($charset) - { - $this->_hdrCharset = $charset; - } - - /** - * Get the character set to use when outputting MIME headers. - * - * @return string The character set. If no preferred character set has - * been set, returns null. - */ - public function getHeaderCharset() - { - return is_null($this->_hdrCharset) - ? $this->getCharset() - : $this->_hdrCharset; - } - - /** - * Set the language(s) of this part. - * - * @param mixed $lang A language string, or an array of language - * strings. - */ - public function setLanguage($lang) - { - $this->_headers->addHeaderOb( - new Horde_Mime_Headers_ContentLanguage('', $lang) - ); - } - - /** - * Get the language(s) of this part. - * - * @param array The list of languages. - */ - public function getLanguage() - { - return $this->_headers['content-language']->langs; - } - - /** - * Set the content duration of the data contained in this part (see RFC - * 3803). - * - * @param integer $duration The duration of the data, in seconds. If - * null, clears the duration information. - */ - public function setDuration($duration) - { - if (is_null($duration)) { - unset($this->_headers['content-duration']); - } else { - if (!($hdr = $this->_headers['content-duration'])) { - $hdr = new Horde_Mime_Headers_Element_Single( - 'Content-Duration', - '' - ); - $this->_headers->addHeaderOb($hdr); - } - $hdr->setValue($duration); - } - } - - /** - * Get the content duration of the data contained in this part (see RFC - * 3803). - * - * @return integer The duration of the data, in seconds. Returns null if - * there is no duration information. - */ - public function getDuration() - { - return ($hdr = $this->_headers['content-duration']) - ? intval($hdr->value) - : null; - } - - /** - * Set the description of this part. - * - * @param string $description The description of this part. If null, - * deletes the description (@since 2.8.0). - */ - public function setDescription($description) - { - if (is_null($description)) { - unset($this->_headers['content-description']); - } else { - if (!($hdr = $this->_headers['content-description'])) { - $hdr = new Horde_Mime_Headers_ContentDescription(null, ''); - $this->_headers->addHeaderOb($hdr); - } - $hdr->setValue($description); - } - } - - /** - * Get the description of this part. - * - * @param boolean $default If the description parameter doesn't exist, - * should we use the name of the part? - * - * @return string The description of this part. - */ - public function getDescription($default = false) - { - if (($ob = $this->_headers['content-description']) && - strlen($ob->value)) { - return $ob->value; - } - - return $default - ? $this->getName() - : ''; - } - - /** - * Set the transfer encoding to use for this part. - * - * Only needed in the following circumstances: - * 1.) Indicate what the transfer encoding is if the data has not yet been - * set in the object (can only be set if there presently are not - * any contents). - * 2.) Force the encoding to a certain type on a toString() call (if - * 'send' is true). - * - * @param string $encoding The transfer encoding to use. - * @param array $options Additional options: - * - send: (boolean) If true, use $encoding as the sending encoding. - * DEFAULT: $encoding is used to change the base encoding. - */ - public function setTransferEncoding($encoding, $options = array()) - { - if (empty($encoding) || - (empty($options['send']) && !empty($this->_contents))) { - return; - } - - switch ($encoding = Horde_String::lower($encoding)) { - case '7bit': - case '8bit': - case 'base64': - case 'binary': - case 'quoted-printable': - // Non-RFC types, but old mailers may still use - case 'uuencode': - case 'x-uuencode': - case 'x-uue': - if (empty($options['send'])) { - $this->_transferEncoding = $encoding; - } else { - $this->_temp['sendEncoding'] = $encoding; - } - break; - - default: - if (empty($options['send'])) { - /* RFC 2045: Any entity with unrecognized encoding must be - * treated as if it has a Content-Type of - * "application/octet-stream" regardless of what the - * Content-Type field actually says. */ - $this->setType('application/octet-stream'); - $this->_transferEncoding = null; - } - break; - } - } - - /** - * Get a list of all MIME subparts. - * - * @return array An array of the Horde_Mime_Part subparts. - */ - public function getParts() - { - return $this->_parts; - } - - /** - * Add/remove a content type parameter to this part. - * - * @param string $label The content-type parameter label. - * @param string $data The content-type parameter data. If null, removes - * the parameter (@since 2.8.0). - */ - public function setContentTypeParameter($label, $data) - { - $ct = $this->_headers['content-type']; - - if (is_null($data)) { - unset($ct[$label]); - } elseif (strlen($data)) { - $ct[$label] = $data; - } - } - - /** - * Get a content type parameter from this part. - * - * @param string $label The content type parameter label. - * - * @return string The data requested. - * Returns null if $label is not set. - */ - public function getContentTypeParameter($label) - { - $ct = $this->_headers['content-type']; - return $ct[$label]; - } - - /** - * Get all parameters from the Content-Type header. - * - * @return array An array of all the parameters - * Returns the empty array if no parameters set. - */ - public function getAllContentTypeParameters() - { - return $this->_headers['content-type']->params; - } - - /** - * Sets a new string to use for EOLs. - * - * @param string $eol The string to use for EOLs. - */ - public function setEOL($eol) - { - $this->_eol = $eol; - } - - /** - * Get the string to use for EOLs. - * - * @return string The string to use for EOLs. - */ - public function getEOL() - { - return $this->_eol; - } - - /** - * Returns a Horde_Mime_Header object containing all MIME headers needed - * for the part. - * - * @param array $options Additional options: - * - encode: (integer) A mask of allowable encodings. - * DEFAULT: Auto-determined - * - headers: (Horde_Mime_Headers) The object to add the MIME headers - * to. - * DEFAULT: Add headers to a new object - * - * @return Horde_Mime_Headers A Horde_Mime_Headers object. - */ - public function addMimeHeaders($options = array()) - { - if (empty($options['headers'])) { - $headers = new Horde_Mime_Headers(); - } else { - $headers = $options['headers']; - $headers->removeHeader('Content-Disposition'); - $headers->removeHeader('Content-Transfer-Encoding'); - } - - /* Add the mandatory Content-Type header. */ - $ct = $this->_headers['content-type']; - $headers->addHeaderOb($ct); - - /* Add the language(s), if set. (RFC 3282 [2]) */ - if ($hdr = $this->_headers['content-language']) { - $headers->addHeaderOb($hdr); - } - - /* Get the description, if any. */ - if ($hdr = $this->_headers['content-description']) { - $headers->addHeaderOb($hdr); - } - - /* Set the duration, if it exists. (RFC 3803) */ - if ($hdr = $this->_headers['content-duration']) { - $headers->addHeaderOb($hdr); - } - - /* Per RFC 2046[4], this MUST appear in the base message headers. */ - if ($this->_status & self::STATUS_BASEPART) { - $headers->addHeaderOb(Horde_Mime_Headers_MimeVersion::create()); - } - - /* message/* parts require no additional header information. */ - if ($ct->ptype === 'message') { - return $headers; - } - - /* RFC 2183 [2] indicates that default is no requested disposition - - * the receiving MUA is responsible for display choice. */ - $cd = $this->_headers['content-disposition']; - if (!$cd->isDefault()) { - $headers->addHeaderOb($cd); - } - - /* Add transfer encoding information. RFC 2045 [6.1] indicates that - * default is 7bit. No need to send the header in this case. */ - $cte = new Horde_Mime_Headers_ContentTransferEncoding( - null, - $this->_getTransferEncoding( - empty($options['encode']) ? null : $options['encode'] - ) - ); - if (!$cte->isDefault()) { - $headers->addHeaderOb($cte); - } - - /* Add content ID information. */ - if ($hdr = $this->_headers['content-id']) { - $headers->addHeaderOb($hdr); - } - - return $headers; - } - - /** - * Return the entire part in MIME format. - * - * @param array $options Additional options: - * - canonical: (boolean) Returns the encoded part in strict RFC 822 & - * 2045 output - namely, all newlines end with the - * canonical sequence. - * DEFAULT: false - * - defserver: (string) The default server to use when creating the - * header string. - * DEFAULT: none - * - encode: (integer) A mask of allowable encodings. - * DEFAULT: self::ENCODE_7BIT - * - headers: (mixed) Include the MIME headers? If true, create a new - * headers object. If a Horde_Mime_Headers object, add MIME - * headers to this object. If a string, use the string - * verbatim. - * DEFAULT: true - * - id: (string) Return only this MIME ID part. - * DEFAULT: Returns the base part. - * - stream: (boolean) Return a stream resource. - * DEFAULT: false - * - * @return mixed The MIME string (returned as a resource if $stream is - * true). - */ - public function toString($options = array()) - { - $eol = $this->getEOL(); - $isbase = true; - $oldbaseptr = null; - $parts = $parts_close = array(); - - if (isset($options['id'])) { - $id = $options['id']; - if (!($part = $this[$id])) { - return $part; - } - unset($options['id']); - $contents = $part->toString($options); - - $prev_id = Horde_Mime::mimeIdArithmetic($id, 'up', array('norfc822' => true)); - $prev_part = ($prev_id == $this->getMimeId()) - ? $this - : $this[$prev_id]; - if (!$prev_part) { - return $contents; - } - - $boundary = trim($this->getContentTypeParameter('boundary'), '"'); - $parts = array( - $eol . '--' . $boundary . $eol, - $contents - ); - - if (!isset($this[Horde_Mime::mimeIdArithmetic($id, 'next')])) { - $parts[] = $eol . '--' . $boundary . '--' . $eol; - } - } else { - if ($isbase = empty($options['_notbase'])) { - $headers = !empty($options['headers']) - ? $options['headers'] - : false; - - if (empty($options['encode'])) { - $options['encode'] = null; - } - if (empty($options['defserver'])) { - $options['defserver'] = null; - } - $options['headers'] = true; - $options['_notbase'] = true; - } else { - $headers = true; - $oldbaseptr = &$options['_baseptr']; - } - - $this->_temp['toString'] = ''; - $options['_baseptr'] = &$this->_temp['toString']; - - /* Any information about a message is embedded in the message - * contents themself. Simply output the contents of the part - * directly and return. */ - $ptype = $this->getPrimaryType(); - if ($ptype == 'message') { - $parts[] = $this->_contents; - } else { - if (!empty($this->_contents)) { - $encoding = $this->_getTransferEncoding($options['encode']); - switch ($encoding) { - case '8bit': - if (empty($options['_baseptr'])) { - $options['_baseptr'] = '8bit'; - } - break; - - case 'binary': - $options['_baseptr'] = 'binary'; - break; - } - - $parts[] = $this->_transferEncode($this->_contents, $encoding); - - /* If not using $this->_contents, we can close the stream - * when finished. */ - if ($this->_temp['transferEncodeClose']) { - $parts_close[] = end($parts); - } - } - - /* Deal with multipart messages. */ - if ($ptype == 'multipart') { - if (empty($this->_contents)) { - $parts[] = 'This message is in MIME format.' . $eol; - } - - $boundary = trim($this->getContentTypeParameter('boundary'), '"'); - - /* If base part is multipart/digest, children should not - * have content-type (automatically treated as - * message/rfc822; RFC 2046 [5.1.5]). */ - if ($this->getSubType() === 'digest') { - $options['is_digest'] = true; - } - - foreach ($this as $part) { - $parts[] = $eol . '--' . $boundary . $eol; - $tmp = $part->toString($options); - if ($part->getEOL() != $eol) { - $tmp = $this->replaceEOL($tmp, $eol, !empty($options['stream'])); - } - if (!empty($options['stream'])) { - $parts_close[] = $tmp; - } - $parts[] = $tmp; - } - $parts[] = $eol . '--' . $boundary . '--' . $eol; - } - } - - if (is_string($headers)) { - array_unshift($parts, $headers); - } elseif ($headers) { - $hdr_ob = $this->addMimeHeaders(array( - 'encode' => $options['encode'], - 'headers' => ($headers === true) ? null : $headers - )); - if (!$isbase && !empty($options['is_digest'])) { - unset($hdr_ob['content-type']); - } - if (!empty($this->_temp['toString'])) { - $hdr_ob->addHeader( - 'Content-Transfer-Encoding', - $this->_temp['toString'] - ); - } - array_unshift($parts, $hdr_ob->toString(array( - 'canonical' => ($eol == self::RFC_EOL), - 'charset' => $this->getHeaderCharset(), - 'defserver' => $options['defserver'] - ))); - } - } - - $newfp = $this->_writeStream($parts); - - array_map('fclose', $parts_close); - - if (!is_null($oldbaseptr)) { - switch ($this->_temp['toString']) { - case '8bit': - if (empty($oldbaseptr)) { - $oldbaseptr = '8bit'; - } - break; - - case 'binary': - $oldbaseptr = 'binary'; - break; - } - } - - if ($isbase && !empty($options['canonical'])) { - return $this->replaceEOL($newfp, self::RFC_EOL, !empty($options['stream'])); - } - - return empty($options['stream']) - ? $this->_readStream($newfp) - : $newfp; - } - - /** - * Get the transfer encoding for the part based on the user requested - * transfer encoding and the current contents of the part. - * - * @param integer $encode A mask of allowable encodings. - * - * @return string The transfer-encoding of this part. - */ - protected function _getTransferEncoding($encode = self::ENCODE_7BIT) - { - if (!empty($this->_temp['sendEncoding'])) { - return $this->_temp['sendEncoding']; - } elseif (!empty($this->_temp['sendTransferEncoding'][$encode])) { - return $this->_temp['sendTransferEncoding'][$encode]; - } - - if (empty($this->_contents)) { - $encoding = '7bit'; - } else { - switch ($this->getPrimaryType()) { - case 'message': - case 'multipart': - /* RFC 2046 [5.2.1] - message/rfc822 messages only allow 7bit, - * 8bit, and binary encodings. If the current encoding is - * either base64 or q-p, switch it to 8bit instead. - * RFC 2046 [5.2.2, 5.2.3, 5.2.4] - All other messages - * only allow 7bit encodings. - * - * TODO: What if message contains 8bit characters and we are - * in strict 7bit mode? Not sure there is anything we can do - * in that situation, especially for message/rfc822 parts. - * - * These encoding will be figured out later (via toString()). - * They are limited to 7bit, 8bit, and binary. Default to - * '7bit' per RFCs. */ - $default_8bit = 'base64'; - $encoding = '7bit'; - break; - - case 'text': - $default_8bit = 'quoted-printable'; - $encoding = '7bit'; - break; - - default: - $default_8bit = 'base64'; - /* If transfer encoding has changed from the default, use that - * value. */ - $encoding = ($this->_transferEncoding == self::DEFAULT_ENCODING) - ? 'base64' - : $this->_transferEncoding; - break; - } - - switch ($encoding) { - case 'base64': - case 'binary': - break; - - default: - $encoding = $this->_scanStream($this->_contents); - break; - } - - switch ($encoding) { - case 'base64': - case 'binary': - /* If the text is longer than 998 characters between - * linebreaks, use quoted-printable encoding to ensure the - * text will not be chopped (i.e. by sendmail if being - * sent as mail text). */ - $encoding = $default_8bit; - break; - - case '8bit': - $encoding = (($encode & self::ENCODE_8BIT) || ($encode & self::ENCODE_BINARY)) - ? '8bit' - : $default_8bit; - break; - } - } - - $this->_temp['sendTransferEncoding'][$encode] = $encoding; - - return $encoding; - } - - /** - * Replace newlines in this part's contents with those specified by either - * the given newline sequence or the part's current EOL setting. - * - * @param mixed $text The text to replace. Either a string or a - * stream resource. If a stream, and returning - * a string, will close the stream when done. - * @param string $eol The EOL sequence to use. If not present, uses - * the part's current EOL setting. - * @param boolean $stream If true, returns a stream resource. - * - * @return string The text with the newlines replaced by the desired - * newline sequence (returned as a stream resource if - * $stream is true). - */ - public function replaceEOL($text, $eol = null, $stream = false) - { - if (is_null($eol)) { - $eol = $this->getEOL(); - } - - stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol'); - $fp = $this->_writeStream($text, array( - 'filter' => array( - 'horde_eol' => array('eol' => $eol) - ) - )); - - return $stream ? $fp : $this->_readStream($fp, true); - } - - /** - * Determine the size of this MIME part and its child members. - * - * @todo Remove $approx parameter. - * - * @param boolean $approx If true, determines an approximate size for - * parts consisting of base64 encoded data. - * - * @return integer Size of the part, in bytes. - */ - public function getBytes($approx = false) - { - if ($this->getPrimaryType() == 'multipart') { - if (isset($this->_bytes)) { - return $this->_bytes; - } - - $bytes = 0; - foreach ($this as $part) { - $bytes += $part->getBytes($approx); - } - return $bytes; - } - - if ($this->_contents) { - fseek($this->_contents, 0, SEEK_END); - $bytes = ftell($this->_contents); - } else { - $bytes = $this->_bytes; - - /* Base64 transfer encoding is approx. 33% larger than original - * data size (RFC 2045 [6.8]). */ - if ($approx && ($this->_transferEncoding == 'base64')) { - $bytes *= 0.75; - } - } - - return intval($bytes); - } - - /** - * Explicitly set the size (in bytes) of this part. This value will only - * be returned (via getBytes()) if there are no contents currently set. - * - * This function is useful for setting the size of the part when the - * contents of the part are not fully loaded (i.e. creating a - * Horde_Mime_Part object from IMAP header information without loading the - * data of the part). - * - * @param integer $bytes The size of this part in bytes. - */ - public function setBytes($bytes) - { - /* Consider 'size' disposition parameter to be the canonical size. - * Only set bytes if that value doesn't exist. */ - if (!$this->getDispositionParameter('size')) { - $this->setDispositionParameter('size', $bytes); - } - } - - /** - * Output the size of this MIME part in KB. - * - * @todo Remove $approx parameter. - * - * @param boolean $approx If true, determines an approximate size for - * parts consisting of base64 encoded data. - * - * @return string Size of the part in KB. - */ - public function getSize($approx = false) - { - if (!($bytes = $this->getBytes($approx))) { - return 0; - } - - $localeinfo = Horde_Nls::getLocaleInfo(); - - // TODO: Workaround broken number_format() prior to PHP 5.4.0. - return str_replace( - array('X', 'Y'), - array($localeinfo['decimal_point'], $localeinfo['thousands_sep']), - number_format(ceil($bytes / 1024), 0, 'X', 'Y') - ); - } - - /** - * Sets the Content-ID header for this part. - * - * @param string $cid Use this CID (if not already set). Else, generate - * a random CID. - * - * @return string The Content-ID for this part. - */ - public function setContentId($cid = null) - { - if (!is_null($id = $this->getContentId())) { - return $id; - } - - $this->_headers->addHeaderOb( - is_null($cid) - ? Horde_Mime_Headers_ContentId::create() - : new Horde_Mime_Headers_ContentId(null, $cid) - ); - - return $this->getContentId(); - } - - /** - * Returns the Content-ID for this part. - * - * @return string The Content-ID for this part (null if not set). - */ - public function getContentId() - { - return ($hdr = $this->_headers['content-id']) - ? trim($hdr->value, '<>') - : null; - } - - /** - * Alter the MIME ID of this part. - * - * @param string $mimeid The MIME ID. - */ - public function setMimeId($mimeid) - { - $this->_mimeid = $mimeid; - } - - /** - * Returns the MIME ID of this part. - * - * @return string The MIME ID. - */ - public function getMimeId() - { - return $this->_mimeid; - } - - /** - * Build the MIME IDs for this part and all subparts. - * - * @param string $id The ID of this part. - * @param boolean $rfc822 Is this a message/rfc822 part? - */ - public function buildMimeIds($id = null, $rfc822 = false) - { - $this->_status &= ~self::STATUS_REINDEX; - - if (is_null($id)) { - $rfc822 = true; - $id = ''; - } - - if ($rfc822) { - if (empty($this->_parts) && - ($this->getPrimaryType() != 'multipart')) { - $this->setMimeId($id . '1'); - } else { - if (empty($id) && ($this->getType() == 'message/rfc822')) { - $this->setMimeId('1.0'); - } else { - $this->setMimeId($id . '0'); - } - $i = 1; - foreach ($this as $val) { - $val->buildMimeIds($id . ($i++)); - } - } - } else { - $this->setMimeId($id); - $id = $id - ? ((substr($id, -2) === '.0') ? substr($id, 0, -1) : ($id . '.')) - : ''; - - if (count($this)) { - if ($this->getType() == 'message/rfc822') { - $this->rewind(); - $this->current()->buildMimeIds($id, true); - } else { - $i = 1; - foreach ($this as $val) { - $val->buildMimeIds($id . ($i++)); - } - } - } - } - } - - /** - * Is this the base MIME part? - * - * @param boolean $base True if this is the base MIME part. - */ - public function isBasePart($base) - { - if (empty($base)) { - $this->_status &= ~self::STATUS_BASEPART; - } else { - $this->_status |= self::STATUS_BASEPART; - } - } - - /** - * Determines if this MIME part is an attachment for display purposes. - * - * @since Horde_Mime 2.10.0 - * - * @return boolean True if this part should be considered an attachment. - */ - public function isAttachment() - { - $type = $this->getType(); - - switch ($type) { - case 'application/ms-tnef': - case 'application/pgp-keys': - case 'application/vnd.ms-tnef': - return false; - } - - if ($this->parent) { - switch ($this->parent->getType()) { - case 'multipart/encrypted': - switch ($type) { - case 'application/octet-stream': - return false; - } - break; - - case 'multipart/signed': - switch ($type) { - case 'application/pgp-signature': - case 'application/pkcs7-signature': - case 'application/x-pkcs7-signature': - return false; - } - break; - } - } - - switch ($this->getDisposition()) { - case 'attachment': - return true; - } - - switch ($this->getPrimaryType()) { - case 'application': - if (strlen($this->getName())) { - return true; - } - break; - - case 'audio': - case 'video': - return true; - - case 'multipart': - return false; - } - - return false; - } - - /** - * Set a piece of metadata on this object. - * - * @param string $key The metadata key. - * @param mixed $data The metadata. If null, clears the key. - */ - public function setMetadata($key, $data = null) - { - if (is_null($data)) { - unset($this->_metadata[$key]); - } else { - $this->_metadata[$key] = $data; - } - } - - /** - * Retrieves metadata from this object. - * - * @param string $key The metadata key. - * - * @return mixed The metadata, or null if it doesn't exist. - */ - public function getMetadata($key) - { - return isset($this->_metadata[$key]) - ? $this->_metadata[$key] - : null; - } - - /** - * Sends this message. - * - * @param string $email The address list to send to. - * @param Horde_Mime_Headers $headers The Horde_Mime_Headers object - * holding this message's headers. - * @param Horde_Mail_Transport $mailer A Horde_Mail_Transport object. - * @param array $opts Additional options: - *
-     *   - broken_rfc2231: (boolean) Attempt to work around non-RFC
-     *                     2231-compliant MUAs by generating both a RFC
-     *                     2047-like parameter name and also the correct RFC
-     *                     2231 parameter (@since 2.5.0).
-     *                     DEFAULT: false
-     *   - encode: (integer) The encoding to use. A mask of self::ENCODE_*
-     *             values.
-     *             DEFAULT: Auto-determined based on transport driver.
-     * 
- * - * @throws Horde_Mime_Exception - * @throws InvalidArgumentException - */ - public function send($email, $headers, Horde_Mail_Transport $mailer, - array $opts = array()) - { - $old_status = $this->_status; - $this->isBasePart(true); - - /* Does the SMTP backend support 8BITMIME (RFC 1652)? */ - $canonical = true; - $encode = self::ENCODE_7BIT; - - if (isset($opts['encode'])) { - /* Always allow 7bit encoding. */ - $encode |= $opts['encode']; - } elseif ($mailer instanceof Horde_Mail_Transport_Smtp) { - try { - $smtp_ext = $mailer->getSMTPObject()->getServiceExtensions(); - if (isset($smtp_ext['8BITMIME'])) { - $encode |= self::ENCODE_8BIT; - } - } catch (Horde_Mail_Exception $e) {} - $canonical = false; - } elseif ($mailer instanceof Horde_Mail_Transport_Smtphorde) { - try { - if ($mailer->getSMTPObject()->data_8bit) { - $encode |= self::ENCODE_8BIT; - } - } catch (Horde_Mail_Exception $e) {} - $canonical = false; - } - - $msg = $this->toString(array( - 'canonical' => $canonical, - 'encode' => $encode, - 'headers' => false, - 'stream' => true - )); - - /* Add MIME Headers if they don't already exist. */ - if (!isset($headers['MIME-Version'])) { - $headers = $this->addMimeHeaders(array( - 'encode' => $encode, - 'headers' => $headers - )); - } - - if (!empty($this->_temp['toString'])) { - $headers->addHeader( - 'Content-Transfer-Encoding', - $this->_temp['toString'] - ); - switch ($this->_temp['toString']) { - case '8bit': - if ($mailer instanceof Horde_Mail_Transport_Smtp) { - $mailer->addServiceExtensionParameter('BODY', '8BITMIME'); - } - break; - } - } - - $this->_status = $old_status; - $rfc822 = new Horde_Mail_Rfc822(); - try { - $mailer->send($rfc822->parseAddressList($email)->writeAddress(array( - 'encode' => $this->getHeaderCharset() ?: true, - 'idn' => true - )), $headers->toArray(array( - 'broken_rfc2231' => !empty($opts['broken_rfc2231']), - 'canonical' => $canonical, - 'charset' => $this->getHeaderCharset() - )), $msg); - } catch (InvalidArgumentException $e) { - // Try to rebuild the part in case it was due to - // an invalid line length in a rfc822/message attachment. - if ($this->_failed) { - throw $e; - } - $this->_failed = true; - $this->_sanityCheckRfc822Attachments(); - try { - $this->send($email, $headers, $mailer, $opts); - } catch (Horde_Mail_Exception $e) { - throw new Horde_Mime_Exception($e); - } - } catch (Horde_Mail_Exception $e) { - throw new Horde_Mime_Exception($e); - } - } - - /** - * Finds the main "body" text part (if any) in a message. - * "Body" data is the first text part under this part. - * - * @param string $subtype Specifically search for this subtype. - * - * @return mixed The MIME ID of the main body part, or null if a body - * part is not found. - */ - public function findBody($subtype = null) - { - $this->buildMimeIds(); - - foreach ($this->partIterator() as $val) { - $id = $val->getMimeId(); - - if (($val->getPrimaryType() == 'text') && - ((intval($id) === 1) || !$this->getMimeId()) && - (is_null($subtype) || ($val->getSubType() == $subtype)) && - ($val->getDisposition() !== 'attachment')) { - return $id; - } - } - - return null; - } - - /** - * Returns the recursive iterator needed to iterate through this part. - * - * @since 2.8.0 - * - * @param boolean $current Include the current part as the base? - * - * @return Iterator Recursive iterator. - */ - public function partIterator($current = true) - { - $this->_reindex(true); - return new Horde_Mime_Part_Iterator($this, $current); - } - - /** - * Returns a subpart by index. - * - * @return Horde_Mime_Part Part, or null if not found. - */ - public function getPartByIndex($index) - { - if (!isset($this->_parts[$index])) { - return null; - } - - $part = $this->_parts[$index]; - $part->parent = $this; - - return $part; - } - - /** - * Reindexes the MIME IDs, if necessary. - * - * @param boolean $force Reindex if the current part doesn't have an ID. - */ - protected function _reindex($force = false) - { - $id = $this->getMimeId(); - - if (($this->_status & self::STATUS_REINDEX) || - ($force && is_null($id))) { - $this->buildMimeIds( - is_null($id) - ? (($this->getPrimaryType() === 'multipart') ? '0' : '1') - : $id - ); - } - } - - /** - * Write data to a stream. - * - * @param array $data The data to write. Either a stream resource or - * a string. - * @param array $options Additional options: - * - error: (boolean) Catch errors when writing to the stream. Throw an - * ErrorException if an error is found. - * DEFAULT: false - * - filter: (array) Filter(s) to apply to the string. Keys are the - * filter names, values are filter params. - * - fp: (resource) Use this stream instead of creating a new one. - * - * @return resource The stream resource. - * @throws ErrorException - */ - protected function _writeStream($data, $options = array()) - { - if (empty($options['fp'])) { - $fp = fopen('php://temp/maxmemory:' . self::$memoryLimit, 'r+'); - } else { - $fp = $options['fp']; - fseek($fp, 0, SEEK_END); - } - - if (!is_array($data)) { - $data = array($data); - } - - $append_filter = array(); - if (!empty($options['filter'])) { - foreach ($options['filter'] as $key => $val) { - $append_filter[] = stream_filter_append($fp, $key, STREAM_FILTER_WRITE, $val); - } - } - - if (!empty($options['error'])) { - set_error_handler(function($errno, $errstr) { - throw new ErrorException($errstr, $errno); - }); - $error = null; - } - - try { - foreach ($data as $d) { - if (is_resource($d)) { - rewind($d); - while (!feof($d)) { - fwrite($fp, fread($d, 8192)); - } - } elseif (is_string($d)) { - $len = strlen($d); - $i = 0; - while ($i < $len) { - fwrite($fp, substr($d, $i, 8192)); - $i += 8192; - } - } - } - } catch (ErrorException $e) { - $error = $e; - } - - foreach ($append_filter as $val) { - stream_filter_remove($val); - } - - if (!empty($options['error'])) { - restore_error_handler(); - if ($error) { - throw $error; - } - } - - return $fp; - } - - /** - * Read data from a stream. - * - * @param resource $fp An active stream. - * @param boolean $close Close the stream when done reading? - * - * @return string The data from the stream. - */ - protected function _readStream($fp, $close = false) - { - $out = ''; - - if (!is_resource($fp)) { - return $out; - } - - rewind($fp); - while (!feof($fp)) { - $out .= fread($fp, 8192); - } - - if ($close) { - fclose($fp); - } - - return $out; - } - - /** - * Scans a stream for content type. - * - * @param resource $fp A stream resource. - * - * @return mixed Either 'binary', '8bit', or false. - */ - protected function _scanStream($fp) - { - rewind($fp); - - stream_filter_register( - 'horde_mime_scan_stream', - 'Horde_Mime_Filter_Encoding' - ); - $filter_params = new stdClass; - $filter = stream_filter_append( - $fp, - 'horde_mime_scan_stream', - STREAM_FILTER_READ, - $filter_params - ); - - while (!feof($fp)) { - fread($fp, 8192); - } - - stream_filter_remove($filter); - - return $filter_params->body; - } - - /* Static methods. */ - - /** - * Attempts to build a Horde_Mime_Part object from message text. - * - * @param string $text The text of the MIME message. - * @param array $opts Additional options: - * - forcemime: (boolean) If true, the message data is assumed to be - * MIME data. If not, a MIME-Version header must exist (RFC - * 2045 [4]) to be parsed as a MIME message. - * DEFAULT: false - * - level: (integer) Current nesting level of the MIME data. - * DEFAULT: 0 - * - no_body: (boolean) If true, don't set body contents of parts (since - * 2.2.0). - * DEFAULT: false - * - * @return Horde_Mime_Part A MIME Part object. - * @throws Horde_Mime_Exception - */ - public static function parseMessage($text, array $opts = array()) - { - /* Mini-hack to get a blank Horde_Mime part so we can call - * replaceEOL(). Convert to EOL, since that is the expected EOL for - * use internally within a Horde_Mime_Part object. */ - $part = new Horde_Mime_Part(); - $rawtext = $part->replaceEOL($text, self::EOL); - - /* Find the header. */ - $hdr_pos = self::_findHeader($rawtext, self::EOL); - - unset($opts['ctype']); - $ob = self::_getStructure(substr($rawtext, 0, $hdr_pos), substr($rawtext, $hdr_pos + 2), $opts); - $ob->buildMimeIds(); - return $ob; - } - - /** - * Creates a MIME object from the text of one part of a MIME message. - * - * @param string $header The header text. - * @param string $body The body text. - * @param array $opts Additional options: - *
-     *   - ctype: (string) The default content-type.
-     *   - forcemime: (boolean) If true, the message data is assumed to be
-     *                MIME data. If not, a MIME-Version header must exist to
-     *                be parsed as a MIME message.
-     *   - level: (integer) Current nesting level.
-     *   - no_body: (boolean) If true, don't set body contents of parts.
-     * 
- * - * @return Horde_Mime_Part The MIME part object. - */ - protected static function _getStructure($header, $body, - array $opts = array()) - { - $opts = array_merge(array( - 'ctype' => 'text/plain', - 'forcemime' => false, - 'level' => 0, - 'no_body' => false - ), $opts); - - /* Parse headers text into a Horde_Mime_Headers object. */ - $hdrs = Horde_Mime_Headers::parseHeaders($header); - - $ob = new Horde_Mime_Part(); - - /* This is not a MIME message. */ - if (!$opts['forcemime'] && !isset($hdrs['MIME-Version'])) { - $ob->setType('text/plain'); - - if ($len = strlen($body)) { - if ($opts['no_body']) { - $ob->setBytes($len); - } else { - $ob->setContents($body); - } - } - - return $ob; - } - - /* Content type. */ - if ($tmp = $hdrs['Content-Type']) { - $ob->setType($tmp->value); - foreach ($tmp->params as $key => $val) { - $ob->setContentTypeParameter($key, $val); - } - } else { - $ob->setType($opts['ctype']); - } - - /* Content transfer encoding. */ - if ($tmp = $hdrs['Content-Transfer-Encoding']) { - $ob->setTransferEncoding(strval($tmp)); - } - - /* Content-Description. */ - if ($tmp = $hdrs['Content-Description']) { - $ob->setDescription(strval($tmp)); - } - - /* Content-Disposition. */ - if ($tmp = $hdrs['Content-Disposition']) { - $ob->setDisposition($tmp->value); - foreach ($tmp->params as $key => $val) { - $ob->setDispositionParameter($key, $val); - } - } - - /* Content-Duration */ - if ($tmp = $hdrs['Content-Duration']) { - $ob->setDuration(strval($tmp)); - } - - /* Content-ID. */ - if ($tmp = $hdrs['Content-Id']) { - $ob->setContentId(strval($tmp)); - } - - if (($len = strlen($body)) && ($ob->getPrimaryType() != 'multipart')) { - if ($opts['no_body']) { - $ob->setBytes($len); - } else { - $ob->setContents($body); - } - } - - if (++$opts['level'] >= self::NESTING_LIMIT) { - return $ob; - } - - /* Process subparts. */ - switch ($ob->getPrimaryType()) { - case 'message': - if ($ob->getSubType() == 'rfc822') { - $ob[] = self::parseMessage($body, array( - 'forcemime' => true, - 'no_body' => $opts['no_body'] - )); - } - break; - - case 'multipart': - $boundary = $ob->getContentTypeParameter('boundary'); - if (!is_null($boundary)) { - foreach (self::_findBoundary($body, 0, $boundary) as $val) { - if (!isset($val['length'])) { - break; - } - $subpart = substr($body, $val['start'], $val['length']); - $hdr_pos = self::_findHeader($subpart, self::EOL); - $ob[] = self::_getStructure( - substr($subpart, 0, $hdr_pos), - substr($subpart, $hdr_pos + 2), - array( - 'ctype' => ($ob->getSubType() == 'digest') ? 'message/rfc822' : 'text/plain', - 'forcemime' => true, - 'level' => $opts['level'], - 'no_body' => $opts['no_body'] - ) - ); - } - } - break; - } - - return $ob; - } - - /** - * Attempts to obtain the raw text of a MIME part. - * - * @param mixed $text The full text of the MIME message. The text is - * assumed to be MIME data (no MIME-Version checking - * is performed). It can be either a stream or a - * string. - * @param string $type Either 'header' or 'body'. - * @param string $id The MIME ID. - * - * @return string The raw text. - * @throws Horde_Mime_Exception - */ - public static function getRawPartText($text, $type, $id) - { - /* Mini-hack to get a blank Horde_Mime part so we can call - * replaceEOL(). From an API perspective, getRawPartText() should be - * static since it is not working on MIME part data. */ - $part = new Horde_Mime_Part(); - $rawtext = $part->replaceEOL($text, self::RFC_EOL); - - /* We need to carry around the trailing "\n" because this is needed - * to correctly find the boundary string. */ - $hdr_pos = self::_findHeader($rawtext, self::RFC_EOL); - $curr_pos = $hdr_pos + 3; - - if ($id == 0) { - switch ($type) { - case 'body': - return substr($rawtext, $curr_pos + 1); - - case 'header': - return trim(substr($rawtext, 0, $hdr_pos)); - } - } - - $hdr_ob = Horde_Mime_Headers::parseHeaders(trim(substr($rawtext, 0, $hdr_pos))); - - /* If this is a message/rfc822, pass the body into the next loop. - * Don't decrement the ID here. */ - if (($ct = $hdr_ob['Content-Type']) && ($ct == 'message/rfc822')) { - return self::getRawPartText( - substr($rawtext, $curr_pos + 1), - $type, - $id - ); - } - - $base_pos = strpos($id, '.'); - $orig_id = $id; - - if ($base_pos !== false) { - $id = substr($id, $base_pos + 1); - $base_pos = substr($orig_id, 0, $base_pos); - } else { - $base_pos = $id; - $id = 0; - } - - if ($ct && !isset($ct->params['boundary'])) { - if ($orig_id == '1') { - return substr($rawtext, $curr_pos + 1); - } - - throw new Horde_Mime_Exception('Could not find MIME part.'); - } - - $b_find = self::_findBoundary( - $rawtext, - $curr_pos, - $ct->params['boundary'], - $base_pos - ); - - if (!isset($b_find[$base_pos])) { - throw new Horde_Mime_Exception('Could not find MIME part.'); - } - - return self::getRawPartText( - substr( - $rawtext, - $b_find[$base_pos]['start'], - $b_find[$base_pos]['length'] - 1 - ), - $type, - $id - ); - } - - /** - * Find the location of the end of the header text. - * - * @param string $text The text to search. - * @param string $eol The EOL string. - * - * @return integer Header position. - */ - protected static function _findHeader($text, $eol) - { - $hdr_pos = strpos($text, $eol . $eol); - return ($hdr_pos === false) - ? strlen($text) - : $hdr_pos; - } - - /** - * Find the location of the next boundary string. - * - * @param string $text The text to search. - * @param integer $pos The current position in $text. - * @param string $boundary The boundary string. - * @param integer $end If set, return after matching this many - * boundaries. - * - * @return array Keys are the boundary number, values are an array with - * two elements: 'start' and 'length'. - */ - protected static function _findBoundary($text, $pos, $boundary, - $end = null) - { - $i = 0; - $out = array(); - - $search = "--" . $boundary; - $search_len = strlen($search); - - while (($pos = strpos($text, $search, $pos)) !== false) { - /* Boundary needs to appear at beginning of string or right after - * a LF. */ - if (($pos != 0) && ($text[$pos - 1] != "\n")) { - continue; - } - - if (isset($out[$i])) { - $out[$i]['length'] = $pos - $out[$i]['start'] - 1; - } - - if (!is_null($end) && ($end == $i)) { - break; - } - - $pos += $search_len; - if (isset($text[$pos])) { - switch ($text[$pos]) { - case "\r": - $pos += 2; - $out[++$i] = array('start' => $pos); - break; - - case "\n": - $out[++$i] = array('start' => ++$pos); - break; - - case '-': - return $out; - } - } - } - - return $out; - } - - /** - * Re-enocdes message/rfc822 parts in case there was e.g., some broken - * line length in the headers of the message in the part. Since we shouldn't - * alter the original message in any way, we simply reset cause the part to - * be encoded as base64 and sent as a application/octet part. - */ - protected function _sanityCheckRfc822Attachments() - { - if ($this->getType() == 'message/rfc822') { - $this->_reEncodeMessageAttachment($this); - return; - } - foreach ($this->getParts() as $part) { - if ($part->getType() == 'message/rfc822') { - $this->_reEncodeMessageAttachment($part); - } - } - return; - } - - /** - * Rebuilds $part and forces it to be a base64 encoded - * application/octet-stream part. - * - * @param Horde_Mime_Part $part The MIME part. - */ - protected function _reEncodeMessageAttachment(Horde_Mime_Part $part) - { - $new_part = Horde_Mime_Part::parseMessage($part->getContents()); - $part->setContents($new_part->getContents(array('stream' => true)), array('encoding' => self::ENCODE_BINARY)); - $part->setTransferEncoding('base64', array('send' => true)); - } - - /* ArrayAccess methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) - { - return ($this[$offset] !== null); - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - $this->_reindex(); - - if (strcmp($offset, $this->getMimeId()) === 0) { - $this->parent = null; - return $this; - } - - foreach ($this->_parts as $val) { - if (strcmp($offset, $val->getMimeId()) === 0) { - $val->parent = $this; - return $val; - } - - if ($found = $val[$offset]) { - return $found; - } - } - - return null; - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - if (is_null($offset)) { - $this->_parts[] = $value; - $this->_status |= self::STATUS_REINDEX; - } elseif ($part = $this[$offset]) { - if ($part->parent === $this) { - if (($k = array_search($part, $this->_parts, true)) !== false) { - $value->setMimeId($part->getMimeId()); - $this->_parts[$k] = $value; - } - } else { - $this->parent[$offset] = $value; - } - } - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetUnset($offset) - { - if ($part = $this[$offset]) { - if ($part->parent === $this) { - if (($k = array_search($part, $this->_parts, true)) !== false) { - unset($this->_parts[$k]); - $this->_parts = array_values($this->_parts); - } - } else { - unset($part->parent[$offset]); - } - $this->_status |= self::STATUS_REINDEX; - } - } - - /* Countable methods. */ - - /** - * Returns the number of child message parts (doesn't include - * grandchildren or more remote ancestors). - * - * @return integer Number of message parts. - */ - #[ReturnTypeWillChange] - public function count() - { - return count($this->_parts); - } - - /* RecursiveIterator methods. */ - - /** - * @since 2.8.0 - */ - #[ReturnTypeWillChange] - public function current() - { - return (($key = $this->key()) === null) - ? null - : $this->getPartByIndex($key); - } - - /** - * @since 2.8.0 - */ - #[ReturnTypeWillChange] - public function key() - { - return (isset($this->_temp['iterate']) && isset($this->_parts[$this->_temp['iterate']])) - ? $this->_temp['iterate'] - : null; - } - - /** - * @since 2.8.0 - */ - #[ReturnTypeWillChange] - public function next() - { - ++$this->_temp['iterate']; - } - - /** - * @since 2.8.0 - */ - #[ReturnTypeWillChange] - public function rewind() - { - $this->_reindex(); - reset($this->_parts); - $this->_temp['iterate'] = key($this->_parts); - } - - /** - * @since 2.8.0 - */ - #[ReturnTypeWillChange] - public function valid() - { - return ($this->key() !== null); - } - - /** - * @since 2.8.0 - */ - #[ReturnTypeWillChange] - public function hasChildren() - { - return (($curr = $this->current()) && count($curr)); - } - - /** - * @since 2.8.0 - */ - #[ReturnTypeWillChange] - public function getChildren() - { - return $this->current(); - } - - /* Serializable methods. */ - - /** - * Serialization. - * - * @return string Serialized data. - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - public function __serialize(): array - { - $data = array( - // Serialized data ID. - self::VERSION, - $this->_bytes, - $this->_eol, - $this->_hdrCharset, - $this->_headers, - $this->_metadata, - $this->_mimeid, - $this->_parts, - $this->_status, - $this->_transferEncoding - ); - - if (!empty($this->_contents)) { - $data[] = $this->_readStream($this->_contents); - } - - return $data; - } - - public function __unserialize(array $data): void - { - if (!isset($data[0]) || ($data[0] != self::VERSION)) { - switch ($data[0]) { - case 1: - $convert = new Horde_Mime_Part_Upgrade_V1($data); - $data = $convert->data; - break; - - default: - $data = null; - break; - } - - if (is_null($data)) { - throw new Exception('Cache version change'); - } - } - - $key = 0; - $this->_bytes = $data[++$key]; - $this->_eol = $data[++$key]; - $this->_hdrCharset = $data[++$key]; - $this->_headers = $data[++$key]; - $this->_metadata = $data[++$key]; - $this->_mimeid = $data[++$key]; - $this->_parts = $data[++$key]; - $this->_status = $data[++$key]; - $this->_transferEncoding = $data[++$key]; - - if (isset($data[++$key])) { - $this->setContents($data[$key]); - } - } - - /** - * Unserialization. - * - * @param string $data Serialized data. - * - * @throws Exception - */ - public function unserialize($data) - { - $data = @unserialize($data); - $this->__unserialize($data); - } - - /* Deprecated elements. */ - - /** - * @deprecated - */ - const UNKNOWN = 'x-unknown'; - - /** - * @deprecated - */ - public static $encodingTypes = array( - '7bit', '8bit', 'base64', 'binary', 'quoted-printable', - // Non-RFC types, but old mailers may still use - 'uuencode', 'x-uuencode', 'x-uue' - ); - - /** - * @deprecated - */ - public static $mimeTypes = array( - 'text', 'multipart', 'message', 'application', 'audio', 'image', - 'video', 'model' - ); - - /** - * @deprecated Use setContentTypeParameter with a null $data value. - */ - public function clearContentTypeParameter($label) - { - $this->setContentTypeParam($label, null); - } - - /** - * @deprecated Use iterator instead. - */ - public function contentTypeMap($sort = true) - { - $map = array(); - - foreach ($this->partIterator() as $val) { - $map[$val->getMimeId()] = $val->getType(); - } - - return $map; - } - - /** - * @deprecated Use array access instead. - */ - public function addPart($mime_part) - { - $this[] = $mime_part; - } - - /** - * @deprecated Use array access instead. - */ - public function getPart($id) - { - return $this[$id]; - } - - /** - * @deprecated Use array access instead. - */ - public function alterPart($id, $mime_part) - { - $this[$id] = $mime_part; - } - - /** - * @deprecated Use array access instead. - */ - public function removePart($id) - { - unset($this[$id]); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Part/Iterator.php b/lib/horde/framework/Horde/Mime/Part/Iterator.php deleted file mode 100644 index 311172fa5c4..00000000000 --- a/lib/horde/framework/Horde/Mime/Part/Iterator.php +++ /dev/null @@ -1,143 +0,0 @@ - - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.9.0 - */ -class Horde_Mime_Part_Iterator -implements Countable, Iterator -{ - /** - * Include the base when iterating? - * - * @var boolean - */ - protected $_includeBase; - - /** - * Base part. - * - * @var Horde_Mime_Part - */ - protected $_part; - - /** - * State data. - * - * @var object - */ - protected $_state; - - /** - * Constructor. - */ - public function __construct(Horde_Mime_Part $part, $base = false) - { - $this->_includeBase = (bool)$base; - $this->_part = $part; - } - - /* Countable methods. */ - - /** - * Returns the number of message parts. - * - * @return integer Number of message parts. - */ - #[ReturnTypeWillChange] - public function count() - { - return count(iterator_to_array($this)); - } - - /* RecursiveIterator methods. */ - - /** - */ - #[ReturnTypeWillChange] - public function current() - { - return $this->valid() - ? $this->_state->current - : null; - } - - /** - */ - #[ReturnTypeWillChange] - public function key() - { - return ($curr = $this->current()) - ? $curr->getMimeId() - : null; - } - - /** - */ - #[ReturnTypeWillChange] - public function next() - { - if (!isset($this->_state)) { - return; - } - - $out = $this->_state->current->getPartByIndex($this->_state->index++); - - if ($out) { - $this->_state->recurse[] = array( - $this->_state->current, - $this->_state->index - ); - $this->_state->current = $out; - $this->_state->index = 0; - } elseif ($tmp = array_pop($this->_state->recurse)) { - $this->_state->current = $tmp[0]; - $this->_state->index = $tmp[1]; - $this->next(); - } else { - unset($this->_state); - } - } - - /** - */ - #[ReturnTypeWillChange] - public function rewind() - { - $this->_state = new stdClass; - $this->_state->current = $this->_part; - $this->_state->index = 0; - $this->_state->recurse = array(); - - if (!$this->_includeBase) { - $this->next(); - } - } - - /** - */ - #[ReturnTypeWillChange] - public function valid() - { - return !empty($this->_state); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Part/Upgrade/V1.php b/lib/horde/framework/Horde/Mime/Part/Upgrade/V1.php deleted file mode 100644 index 1f24af1c14a..00000000000 --- a/lib/horde/framework/Horde/Mime/Part/Upgrade/V1.php +++ /dev/null @@ -1,118 +0,0 @@ - - * @category Horde - * @copyright 2015-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.8.0 - */ -class Horde_Mime_Part_Upgrade_V1 -{ - /** - * Converted data. - * - * @var array - */ - public $data = null; - - /** - * Constructor. - * - * @param array $data V1 data. - */ - public function __construct($data) - { - // Version number - array_shift($data); - - $d = array(); - - $type = array_shift($data); - $subtype = array_shift($data); - - $ct = Horde_Mime_Headers_ContentParam_ContentType::create(); - $d[4] = new Horde_Mime_Headers(); - $d[4]->addHeaderOb($ct); - $ct->setContentParamValue($type . '/' . $subtype); - - $d[9] = array_shift($data); - - if ($lang = array_shift($data)) { - $d[4]->addHeaderOb( - new Horde_Mime_Headers_ContentLanguage('', $lang) - ); - } - - if ($cd = array_shift($data)) { - $hdr = new Horde_Mime_Headers_ContentDescription(null, ''); - $d[4]->addHeaderOb($hdr); - $hdr->setValue($cd); - } - - $cd = new Horde_Mime_Headers_ContentParam_ContentDisposition(null, ''); - $d[4]->addHeaderOb($cd); - $cd->setContentParamValue(array_shift($data)); - - foreach (array_shift($data) as $key => $val) { - $cd[$key] = $val; - } - - foreach (array_shift($data) as $key => $val) { - $ct[$key] = $val; - } - - $d[7] = array_shift($data); - $d[6] = array_shift($data); - $d[2] = array_shift($data); - $d[5] = array_shift($data); - - if ($boundary = array_shift($data)) { - $ct['boundary'] = $boundary; - } - - $d[1] = array_shift($data); - - if ($cid = array_shift($data)) { - $hdr = new Horde_Mime_Headers_ContentId(null, $cid); - $d[4]->addHeaderOb($hdr); - } - - if ($cd = array_shift($data)) { - $hdr = new Horde_Mime_Headers_Element_Single('Content-Duration', ''); - $d[4]->addHeaderOb($hdr); - $hdr->setValue($cd); - } - - $d[8] = 0; - if (array_shift($data)) { - $d[8] |= STATUS_REINDEX; - } - if (array_shift($data)) { - $d[8] |= STATUS_BASEPART; - } - - $d[3] = array_shift($data); - - if (count($data)) { - $d[10] = reset($data); - } - - $this->data = $d; - } - -} diff --git a/lib/horde/framework/Horde/Mime/QuotedPrintable.php b/lib/horde/framework/Horde/Mime/QuotedPrintable.php deleted file mode 100644 index bc18496efaf..00000000000 --- a/lib/horde/framework/Horde/Mime/QuotedPrintable.php +++ /dev/null @@ -1,67 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_QuotedPrintable -{ - /** - * Decodes quoted-printable data. - * - * @param string $data The Q-P data to decode. - * - * @return string The decoded text. - */ - public static function decode($data) - { - return quoted_printable_decode($data); - } - - /** - * Encodes text via quoted-printable encoding. - * - * @param string $text The text to encode (UTF-8). - * @param string $eol The EOL sequence to use. - * @param integer $wrap Wrap a line at this many characters. - * - * @return string The quoted-printable encoded string. - */ - public static function encode($text, $eol = "\n", $wrap = 76) - { - $fp = fopen('php://temp', 'r+'); - stream_filter_append( - $fp, - 'convert.quoted-printable-encode', - STREAM_FILTER_WRITE, - array( - 'line-break-chars' => $eol, - 'line-length' => $wrap - ) - ); - fwrite($fp, $text); - rewind($fp); - $out = stream_get_contents($fp); - fclose($fp); - - return $out; - } - -} diff --git a/lib/horde/framework/Horde/Mime/Related.php b/lib/horde/framework/Horde/Mime/Related.php deleted file mode 100644 index 252919d98e5..00000000000 --- a/lib/horde/framework/Horde/Mime/Related.php +++ /dev/null @@ -1,162 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ -class Horde_Mime_Related implements IteratorAggregate -{ - /** - * Content IDs. - * - * @var array - */ - protected $_cids = array(); - - /** - * Start ID. - * - * @var string - */ - protected $_start; - - /** - * Constructor. - * - * @param Horde_Mime_Part $mime_part A MIME part object. Must be of - * type multipart/related. - */ - public function __construct(Horde_Mime_Part $mime_part) - { - if ($mime_part->getType() != 'multipart/related') { - throw new InvalidArgumentException('MIME part must be of type multipart/related'); - } - - $id = null; - $ids = array(); - $related_id = $mime_part->getMimeId(); - - /* Build a list of parts -> CIDs. */ - foreach ($mime_part->partIterator() as $val) { - $part_id = $val->getMimeId(); - $ids[] = $part_id; - - if ((strcmp($related_id, $part_id) !== 0) && - ($cid = $val->getContentId())) { - $this->_cids[$part_id] = $cid; - } - } - - /* Look at the 'start' parameter to determine which part to start - * with. If no 'start' parameter, use the first part (RFC 2387 - * [3.1]). */ - if ($start = $mime_part->getContentTypeParameter('start')) { - $id = $this->cidSearch(trim($start, '<> ')); - } - - if (empty($id)) { - reset($ids); - $id = next($ids); - } - - $this->_start = $id; - } - - /** - * Return the start ID. - * - * @return string The start ID. - */ - public function startId() - { - return $this->_start; - } - - /** - * Search for a CID in the related part. - * - * @param string $cid The CID to search for. - * - * @return string The MIME ID or false if not found. - */ - public function cidSearch($cid) - { - return array_search($cid, $this->_cids); - } - - /** - * Scan for CID strings in HTML data and replace with data returned from - * a callback method. - * - * @param mixed $text The HTML text (can be Horde_Domhtml object). - * @param callback $callback Callback method. Receives three arguments: - * MIME ID, the attribute name containing the - * content ID, and the node object. Expects - * return value of URL to display the data. - * @param string $charset HTML data charset. - * - * @return Horde_Domhtml A Horde_Domhtml object. - */ - public function cidReplace($text, $callback, $charset = 'UTF-8') - { - $dom = ($text instanceof Horde_Domhtml) - ? $text - : new Horde_Domhtml($text, $charset); - - foreach ($dom as $node) { - if ($node instanceof DOMElement) { - switch (Horde_String::lower($node->tagName)) { - case 'body': - case 'td': - $this->_cidReplace($node, 'background', $callback); - break; - - case 'img': - $this->_cidReplace($node, 'src', $callback); - break; - } - } - } - - return $dom; - } - - /** - */ - protected function _cidReplace($node, $attribute, $callback) - { - if ($node->hasAttribute($attribute)) { - $val = $node->getAttribute($attribute); - if ((strpos($val, 'cid:') === 0) && - ($id = $this->cidSearch(substr($val, 4)))) { - $node->setAttribute($attribute, call_user_func($callback, $id, $attribute, $node)); - } - } - } - - /* IteratorAggregate method. */ - - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_cids); - } - -} diff --git a/lib/horde/framework/Horde/Mime/Translation.php b/lib/horde/framework/Horde/Mime/Translation.php deleted file mode 100644 index c88a93c9b9d..00000000000 --- a/lib/horde/framework/Horde/Mime/Translation.php +++ /dev/null @@ -1,38 +0,0 @@ - - * @category Horde - * @copyright 2010-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ -class Horde_Mime_Translation extends Horde_Translation_Autodetect -{ - /** - * The translation domain - * - * @var string - */ - protected static $_domain = 'Horde_Mime'; - - /** - * The absolute PEAR path to the translations for the default gettext handler. - * - * @var string - */ - protected static $_pearDirectory = '@data_dir@'; -} diff --git a/lib/horde/framework/Horde/Mime/Uudecode.php b/lib/horde/framework/Horde/Mime/Uudecode.php deleted file mode 100644 index 42368748183..00000000000 --- a/lib/horde/framework/Horde/Mime/Uudecode.php +++ /dev/null @@ -1,131 +0,0 @@ -, Arpad Ray - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - */ - -/** - * Class used to uudecode data. - * - * Needed because PHP's built-in uudecode() method is broken. - * - * @author Chuck Hagenbuch - * @author Aidan Lister - * @author Michael Slusarz - * @author Michael Wallner - * @category Horde - * @copyright 2009-2017 Horde LLC - * @copyright 2004-2007 Aidan Lister , Arpad Ray - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Mime - * @since 2.5.0 - */ -class Horde_Mime_Uudecode implements Countable, IteratorAggregate -{ - const UUENCODE_REGEX = "/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us"; - - /** - * Uudecode data. - * - * A list of arrays, with each array corresponding to a file in the input - * and containing the following keys: - * - data: (string) Unencoded data. - * - name: (string) Filename. - * - perms: (string) Octal permissions. - * - * @var array - */ - protected $_data = array(); - - /** - * Scans $input for uuencoded data and converts it to unencoded data. - * - * @param string $input The input data - */ - public function __construct($input) - { - /* Find all uuencoded sections. */ - if (preg_match_all(self::UUENCODE_REGEX, $input, $matches, PREG_SET_ORDER)) { - foreach ($matches as $v) { - $this->_data[] = array( - 'data' => $this->_uudecode($v[3]), - 'name' => $v[2], - 'perm' => $v[1] - ); - } - } - } - - /** - * PHP 5's built-in convert_uudecode() is broken. Need this wrapper. - * - * @param string $input UUencoded input. - * - * @return string Decoded string. - */ - protected function _uudecode($input) - { - $decoded = ''; - - foreach (explode("\n", $input) as $line) { - $c = count($bytes = unpack('c*', substr(trim($line,"\r\n\t"), 1))); - - while ($c % 4) { - $bytes[++$c] = 0; - } - - foreach (array_chunk($bytes, 4) as $b) { - $b0 = ($b[0] == 0x60) ? 0 : $b[0] - 0x20; - $b1 = ($b[1] == 0x60) ? 0 : $b[1] - 0x20; - $b2 = ($b[2] == 0x60) ? 0 : $b[2] - 0x20; - $b3 = ($b[3] == 0x60) ? 0 : $b[3] - 0x20; - - $b0 <<= 2; - $b0 |= ($b1 >> 4) & 0x03; - $b1 <<= 4; - $b1 |= ($b2 >> 2) & 0x0F; - $b2 <<= 6; - $b2 |= $b3 & 0x3F; - - $decoded .= pack('c*', $b0, $b1, $b2); - } - } - - return rtrim($decoded, "\0"); - } - - /* Countable method. */ - - #[ReturnTypeWillChange] - public function count() - { - return count($this->_data); - } - - /* IteratorAggregate method. */ - - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_data); - } - -} diff --git a/lib/horde/framework/Horde/Mime/mime.mapping.php b/lib/horde/framework/Horde/Mime/mime.mapping.php deleted file mode 100644 index 0d3ec85a576..00000000000 --- a/lib/horde/framework/Horde/Mime/mime.mapping.php +++ /dev/null @@ -1,1445 +0,0 @@ -' where is the unknown file extension. - * - * Generated: 12/04/14 00:15:12 by slusarz on bigworm.curecanti.org - * - * @category Horde - * @package Mime - */ -$mime_extension_map = array( - '__MAXPERIOD__' => '1', - '3dml' => 'text/vnd.in3d.3dml', - '3ds' => 'image/x-3ds', - '3g2' => 'video/3gpp2', - '3ga' => 'video/3gpp', - '3gp' => 'video/3gpp', - '3gp2' => 'video/3gpp2', - '3gpp' => 'video/3gpp', - '3gpp2' => 'video/3gpp2', - '7z' => 'application/x-7z-compressed', - 'C' => 'text/x-c++src', - 'Z' => 'application/x-compress', - 'a' => 'application/x-archive', - 'aab' => 'application/x-authorware-bin', - 'aac' => 'audio/x-aac', - 'aam' => 'application/x-authorware-map', - 'aas' => 'application/x-authorware-seg', - 'abw' => 'application/x-abiword', - 'abw.crashed' => 'application/x-abiword', - 'abw.gz' => 'application/x-abiword', - 'ac' => 'application/pkix-attr-cert', - 'ac3' => 'audio/ac3', - 'acc' => 'application/vnd.americandynamics.acc', - 'ace' => 'application/x-ace-compressed', - 'acu' => 'application/vnd.acucobol', - 'acutc' => 'application/vnd.acucorp', - 'adb' => 'text/x-adasrc', - 'adp' => 'audio/adpcm', - 'ads' => 'text/x-adasrc', - 'aep' => 'application/vnd.audiograph', - 'afm' => 'application/x-font-type1', - 'afp' => 'application/vnd.ibm.modcap', - 'ag' => 'image/x-applix-graphics', - 'ahead' => 'application/vnd.ahead.space', - 'ai' => 'application/postscript', - 'aif' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'aiffc' => 'audio/x-aifc', - 'air' => 'application/vnd.adobe.air-application-installer-package+zip', - 'ait' => 'application/vnd.dvb.ait', - 'al' => 'application/x-perl', - 'alz' => 'application/x-alz', - 'ami' => 'application/vnd.amiga.ami', - 'amr' => 'audio/AMR', - 'amz' => 'audio/x-amzxml', - 'ani' => 'application/x-navi-animation', - 'anx' => 'application/annodex', - 'ape' => 'audio/x-ape', - 'apk' => 'application/vnd.android.package-archive', - 'appcache' => 'text/cache-manifest', - 'application' => 'application/x-ms-application', - 'apr' => 'application/vnd.lotus-approach', - 'ar' => 'application/x-archive', - 'arc' => 'application/x-freearc', - 'arj' => 'application/x-arj', - 'arw' => 'image/x-sony-arw', - 'as' => 'application/x-applix-spreadsheet', - 'asc' => 'application/pgp-signature', - 'asf' => 'video/x-ms-asf', - 'asm' => 'text/x-asm', - 'aso' => 'application/vnd.accpac.simply.aso', - 'asp' => 'application/x-asp', - 'ass' => 'text/x-ssa', - 'asx' => 'video/x-ms-asf', - 'atc' => 'application/vnd.acucorp', - 'atom' => 'application/atom+xml', - 'atomcat' => 'application/atomcat+xml', - 'atomsvc' => 'application/atomsvc+xml', - 'atx' => 'application/vnd.antix.game-component', - 'au' => 'audio/basic', - 'avf' => 'video/x-msvideo', - 'avi' => 'video/x-msvideo', - 'aw' => 'application/applixware', - 'awb' => 'audio/AMR-WB', - 'awk' => 'application/x-awk', - 'axa' => 'audio/annodex', - 'axv' => 'video/annodex', - 'azf' => 'application/vnd.airzip.filesecure.azf', - 'azs' => 'application/vnd.airzip.filesecure.azs', - 'azw' => 'application/vnd.amazon.ebook', - 'bak' => 'application/x-trash', - 'bat' => 'application/x-msdownload', - 'bcpio' => 'application/x-bcpio', - 'bdf' => 'application/x-font-bdf', - 'bdm' => 'application/vnd.syncml.dm+wbxml', - 'bdmv' => 'video/mp2t', - 'bed' => 'application/vnd.realvnc.bed', - 'bh2' => 'application/vnd.fujitsu.oasysprs', - 'bib' => 'text/x-bibtex', - 'bin' => 'application/octet-stream', - 'blb' => 'application/x-blorb', - 'blend' => 'application/x-blender', - 'blender' => 'application/x-blender', - 'blorb' => 'application/x-blorb', - 'bmi' => 'application/vnd.bmi', - 'bmp' => 'image/bmp', - 'book' => 'application/vnd.framemaker', - 'box' => 'application/vnd.previewsystems.box', - 'boz' => 'application/x-bzip2', - 'bpk' => 'application/octet-stream', - 'btif' => 'image/prs.btif', - 'bz' => 'application/x-bzip', - 'bz2' => 'application/x-bzip2', - 'c' => 'text/x-c', - 'c++' => 'text/x-c++src', - 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', - 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', - 'c4d' => 'application/vnd.clonk.c4group', - 'c4f' => 'application/vnd.clonk.c4group', - 'c4g' => 'application/vnd.clonk.c4group', - 'c4p' => 'application/vnd.clonk.c4group', - 'c4u' => 'application/vnd.clonk.c4group', - 'cab' => 'application/vnd.ms-cab-compressed', - 'caf' => 'audio/x-caf', - 'cap' => 'application/vnd.tcpdump.pcap', - 'car' => 'application/vnd.curl.car', - 'cat' => 'application/vnd.ms-pki.seccat', - 'cb7' => 'application/x-cbr', - 'cba' => 'application/x-cbr', - 'cbl' => 'text/x-cobol', - 'cbr' => 'application/x-cbr', - 'cbt' => 'application/x-cbr', - 'cbz' => 'application/x-cbr', - 'cc' => 'text/x-c', - 'ccmx' => 'application/x-ccmx', - 'cct' => 'application/x-director', - 'ccxml' => 'application/ccxml+xml', - 'cdbcmsg' => 'application/vnd.contact.cmsg', - 'cdf' => 'application/x-netcdf', - 'cdkey' => 'application/vnd.mediastation.cdkey', - 'cdmia' => 'application/cdmi-capability', - 'cdmic' => 'application/cdmi-container', - 'cdmid' => 'application/cdmi-domain', - 'cdmio' => 'application/cdmi-object', - 'cdmiq' => 'application/cdmi-queue', - 'cdr' => 'application/vnd.corel-draw', - 'cdx' => 'chemical/x-cdx', - 'cdxml' => 'application/vnd.chemdraw+xml', - 'cdy' => 'application/vnd.cinderella', - 'cer' => 'application/pkix-cert', - 'cert' => 'application/x-x509-ca-cert', - 'cfs' => 'application/x-cfs-compressed', - 'cgm' => 'image/cgm', - 'chat' => 'application/x-chat', - 'chm' => 'application/vnd.ms-htmlhelp', - 'chrt' => 'application/vnd.kde.kchart', - 'cif' => 'chemical/x-cif', - 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', - 'cil' => 'application/vnd.ms-artgalry', - 'cla' => 'application/vnd.claymore', - 'class' => 'application/java-vm', - 'clkk' => 'application/vnd.crick.clicker.keyboard', - 'clkp' => 'application/vnd.crick.clicker.palette', - 'clkt' => 'application/vnd.crick.clicker.template', - 'clkw' => 'application/vnd.crick.clicker.wordbank', - 'clkx' => 'application/vnd.crick.clicker', - 'clp' => 'application/x-msclip', - 'clpi' => 'video/mp2t', - 'cls' => 'text/x-tex', - 'cmake' => 'text/x-cmake', - 'cmc' => 'application/vnd.cosmocaller', - 'cmdf' => 'chemical/x-cmdf', - 'cml' => 'chemical/x-cml', - 'cmp' => 'application/vnd.yellowriver-custom-menu', - 'cmx' => 'image/x-cmx', - 'cob' => 'text/x-cobol', - 'cod' => 'application/vnd.rim.cod', - 'com' => 'application/x-msdownload', - 'conf' => 'text/plain', - 'cpi' => 'video/mp2t', - 'cpio' => 'application/x-cpio', - 'cpio.gz' => 'application/x-cpio-compressed', - 'cpp' => 'text/x-c', - 'cpt' => 'application/mac-compactpro', - 'cr2' => 'image/x-canon-cr2', - 'crd' => 'application/x-mscardfile', - 'crl' => 'application/pkix-crl', - 'crt' => 'application/x-x509-ca-cert', - 'crw' => 'image/x-canon-crw', - 'cryptonote' => 'application/vnd.rig.cryptonote', - 'cs' => 'text/x-csharp', - 'csh' => 'application/x-csh', - 'csml' => 'chemical/x-csml', - 'csp' => 'application/vnd.commonspace', - 'css' => 'text/css', - 'cst' => 'application/x-director', - 'csv' => 'text/csv', - 'cu' => 'application/cu-seeme', - 'cue' => 'application/x-cue', - 'cur' => 'image/x-win-bitmap', - 'curl' => 'text/vnd.curl', - 'cww' => 'application/prs.cww', - 'cxt' => 'application/x-director', - 'cxx' => 'text/x-c', - 'd' => 'text/x-dsrc', - 'dae' => 'model/vnd.collada+xml', - 'daf' => 'application/vnd.mobius.daf', - 'dar' => 'application/x-dar', - 'dart' => 'application/vnd.dart', - 'dataless' => 'application/vnd.fdsn.seed', - 'davmount' => 'application/davmount+xml', - 'dbf' => 'application/x-dbf', - 'dbk' => 'application/docbook+xml', - 'dc' => 'application/x-dc-rom', - 'dcl' => 'text/x-dcl', - 'dcm' => 'application/dicom', - 'dcr' => 'application/x-director', - 'dcurl' => 'text/vnd.curl.dcurl', - 'dd2' => 'application/vnd.oma.dd2+xml', - 'ddd' => 'application/vnd.fujixerox.ddd', - 'dds' => 'image/x-dds', - 'deb' => 'application/x-debian-package', - 'def' => 'text/plain', - 'deploy' => 'application/octet-stream', - 'der' => 'application/x-x509-ca-cert', - 'desktop' => 'application/x-desktop', - 'dfac' => 'application/vnd.dreamfactory', - 'dgc' => 'application/x-dgc-compressed', - 'di' => 'text/x-dsrc', - 'dia' => 'application/x-dia-diagram', - 'dic' => 'text/x-c', - 'diff' => 'text/diff', - 'dir' => 'application/x-director', - 'dis' => 'application/vnd.mobius.dis', - 'dist' => 'application/octet-stream', - 'distz' => 'application/octet-stream', - 'divx' => 'video/x-msvideo', - 'djv' => 'image/vnd.djvu', - 'djvu' => 'image/vnd.djvu', - 'dll' => 'application/x-msdownload', - 'dmg' => 'application/x-apple-diskimage', - 'dmp' => 'application/vnd.tcpdump.pcap', - 'dms' => 'application/octet-stream', - 'dna' => 'application/vnd.dna', - 'dng' => 'image/x-adobe-dng', - 'doc' => 'application/msword', - 'docbook' => 'application/x-docbook+xml', - 'docm' => 'application/vnd.ms-word.document.macroenabled.12', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'dot' => 'application/msword', - 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', - 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', - 'dp' => 'application/vnd.osgi.dp', - 'dpg' => 'application/vnd.dpgraph', - 'dra' => 'audio/vnd.dra', - 'dsc' => 'text/prs.lines.tag', - 'dsl' => 'text/x-dsl', - 'dssc' => 'application/dssc+der', - 'dtb' => 'application/x-dtbook+xml', - 'dtd' => 'application/xml-dtd', - 'dts' => 'audio/vnd.dts', - 'dtshd' => 'audio/vnd.dts.hd', - 'dtx' => 'text/x-tex', - 'dump' => 'application/octet-stream', - 'dv' => 'video/dv', - 'dvb' => 'video/vnd.dvb.file', - 'dvi' => 'application/x-dvi', - 'dvi.bz2' => 'application/x-bzdvi', - 'dvi.gz' => 'application/x-gzdvi', - 'dwf' => 'model/vnd.dwf', - 'dwg' => 'image/vnd.dwg', - 'dxf' => 'image/vnd.dxf', - 'dxp' => 'application/vnd.spotfire.dxp', - 'dxr' => 'application/x-director', - 'e' => 'text/x-eiffel', - 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', - 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', - 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', - 'ecma' => 'application/ecmascript', - 'edm' => 'application/vnd.novadigm.edm', - 'edx' => 'application/vnd.novadigm.edx', - 'efif' => 'application/vnd.picsel', - 'egon' => 'application/x-egon', - 'ei6' => 'application/vnd.pg.osasli', - 'eif' => 'text/x-eiffel', - 'el' => 'text/x-emacs-lisp', - 'elc' => 'application/octet-stream', - 'emf' => 'application/x-msmetafile', - 'eml' => 'message/rfc822', - 'emma' => 'application/emma+xml', - 'emp' => 'application/vnd.emusic-emusic_package', - 'emz' => 'application/x-msmetafile', - 'ent' => 'application/xml-external-parsed-entity', - 'eol' => 'audio/vnd.digital-winds', - 'eot' => 'application/vnd.ms-fontobject', - 'eps' => 'application/postscript', - 'eps.bz2' => 'image/x-bzeps', - 'eps.gz' => 'image/x-gzeps', - 'epsf' => 'image/x-eps', - 'epsf.bz2' => 'image/x-bzeps', - 'epsf.gz' => 'image/x-gzeps', - 'epsi' => 'image/x-eps', - 'epsi.bz2' => 'image/x-bzeps', - 'epsi.gz' => 'image/x-gzeps', - 'epub' => 'application/epub+zip', - 'erl' => 'text/x-erlang', - 'es' => 'application/ecmascript', - 'es3' => 'application/vnd.eszigno3+xml', - 'esa' => 'application/vnd.osgi.subsystem', - 'esf' => 'application/vnd.epson.esf', - 'et3' => 'application/vnd.eszigno3+xml', - 'etheme' => 'application/x-e-theme', - 'etx' => 'text/x-setext', - 'eva' => 'application/x-eva', - 'evy' => 'application/x-envoy', - 'exe' => 'application/x-msdownload', - 'exi' => 'application/exi', - 'exr' => 'image/x-exr', - 'ext' => 'application/vnd.novadigm.ext', - 'ez' => 'application/andrew-inset', - 'ez2' => 'application/vnd.ezpix-album', - 'ez3' => 'application/vnd.ezpix-package', - 'f' => 'text/x-fortran', - 'f4a' => 'audio/mp4', - 'f4b' => 'audio/x-m4b', - 'f4v' => 'video/x-f4v', - 'f77' => 'text/x-fortran', - 'f90' => 'text/x-fortran', - 'f95' => 'text/x-fortran', - 'fb2' => 'application/x-fictionbook+xml', - 'fb2.zip' => 'application/x-zip-compressed-fb2', - 'fbs' => 'image/vnd.fastbidsheet', - 'fcdt' => 'application/vnd.adobe.formscentral.fcdt', - 'fcs' => 'application/vnd.isac.fcs', - 'fdf' => 'application/vnd.fdf', - 'fe_launch' => 'application/vnd.denovo.fcselayout-link', - 'fg5' => 'application/vnd.fujitsu.oasysgp', - 'fgd' => 'application/x-director', - 'fh' => 'image/x-freehand', - 'fh4' => 'image/x-freehand', - 'fh5' => 'image/x-freehand', - 'fh7' => 'image/x-freehand', - 'fhc' => 'image/x-freehand', - 'fig' => 'application/x-xfig', - 'fits' => 'image/fits', - 'fl' => 'application/x-fluid', - 'flac' => 'audio/x-flac', - 'flc' => 'video/x-flic', - 'fli' => 'video/x-fli', - 'flo' => 'application/vnd.micrografx.flo', - 'flv' => 'video/x-flv', - 'flw' => 'application/vnd.kde.kivio', - 'flx' => 'text/vnd.fmi.flexstor', - 'fly' => 'text/vnd.fly', - 'fm' => 'application/vnd.framemaker', - 'fnc' => 'application/vnd.frogans.fnc', - 'fo' => 'text/x-xslfo', - 'fodg' => 'application/vnd.oasis.opendocument.graphics-flat-xml', - 'fodp' => 'application/vnd.oasis.opendocument.presentation-flat-xml', - 'fods' => 'application/vnd.oasis.opendocument.spreadsheet-flat-xml', - 'fodt' => 'application/vnd.oasis.opendocument.text-flat-xml', - 'for' => 'text/x-fortran', - 'fpx' => 'image/vnd.fpx', - 'frame' => 'application/vnd.framemaker', - 'fsc' => 'application/vnd.fsc.weblaunch', - 'fst' => 'image/vnd.fst', - 'ftc' => 'application/vnd.fluxtime.clip', - 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', - 'fvt' => 'video/vnd.fvt', - 'fxm' => 'video/x-javafx', - 'fxp' => 'application/vnd.adobe.fxp', - 'fxpl' => 'application/vnd.adobe.fxp', - 'fzs' => 'application/vnd.fuzzysheet', - 'g2w' => 'application/vnd.geoplan', - 'g3' => 'image/g3fax', - 'g3w' => 'application/vnd.geospace', - 'gac' => 'application/vnd.groove-account', - 'gam' => 'application/x-tads', - 'gb' => 'application/x-gameboy-rom', - 'gba' => 'application/x-gba-rom', - 'gbr' => 'application/rpki-ghostbusters', - 'gca' => 'application/x-gca-compressed', - 'gcrd' => 'text/vcard', - 'gdl' => 'model/vnd.gdl', - 'ged' => 'application/x-gedcom', - 'gedcom' => 'application/x-gedcom', - 'gem' => 'application/x-tar', - 'gen' => 'application/x-genesis-rom', - 'geo' => 'application/vnd.dynageo', - 'gex' => 'application/vnd.geometry-explorer', - 'gf' => 'application/x-tex-gf', - 'gg' => 'application/x-sms-rom', - 'ggb' => 'application/vnd.geogebra.file', - 'ggt' => 'application/vnd.geogebra.tool', - 'ghf' => 'application/vnd.groove-help', - 'gif' => 'image/gif', - 'gim' => 'application/vnd.groove-identity-message', - 'glade' => 'application/x-glade', - 'gml' => 'application/gml+xml', - 'gmo' => 'application/x-gettext-translation', - 'gmx' => 'application/vnd.gmx', - 'gnc' => 'application/x-gnucash', - 'gnd' => 'application/gnunet-directory', - 'gnucash' => 'application/x-gnucash', - 'gnumeric' => 'application/x-gnumeric', - 'gnuplot' => 'application/x-gnuplot', - 'go' => 'text/x-go', - 'gp' => 'application/x-gnuplot', - 'gpg' => 'application/pgp-encrypted', - 'gph' => 'application/vnd.flographit', - 'gplt' => 'application/x-gnuplot', - 'gpx' => 'application/gpx+xml', - 'gqf' => 'application/vnd.grafeq', - 'gqs' => 'application/vnd.grafeq', - 'gra' => 'application/x-graphite', - 'gram' => 'application/srgs', - 'gramps' => 'application/x-gramps-xml', - 'gre' => 'application/vnd.geometry-explorer', - 'grv' => 'application/vnd.groove-injector', - 'grxml' => 'application/srgs+xml', - 'gsf' => 'application/x-font-ghostscript', - 'gsm' => 'audio/x-gsm', - 'gtar' => 'application/x-gtar', - 'gtm' => 'application/vnd.groove-tool-message', - 'gtw' => 'model/vnd.gtw', - 'gv' => 'text/vnd.graphviz', - 'gvp' => 'text/x-google-video-pointer', - 'gxf' => 'application/gxf', - 'gxt' => 'application/vnd.geonext', - 'gz' => 'application/x-gzip', - 'h' => 'text/x-c', - 'h++' => 'text/x-c++hdr', - 'h261' => 'video/h261', - 'h263' => 'video/h263', - 'h264' => 'video/h264', - 'h4' => 'application/x-hdf', - 'h5' => 'application/x-hdf', - 'hal' => 'application/vnd.hal+xml', - 'hbci' => 'application/vnd.hbci', - 'hdf' => 'application/x-hdf', - 'hdf4' => 'application/x-hdf', - 'hdf5' => 'application/x-hdf', - 'hh' => 'text/x-c', - 'hlp' => 'application/winhlp', - 'hp' => 'text/x-c++hdr', - 'hpgl' => 'application/vnd.hp-hpgl', - 'hpid' => 'application/vnd.hp-hpid', - 'hpp' => 'text/x-c++hdr', - 'hps' => 'application/vnd.hp-hps', - 'hqx' => 'application/mac-binhex40', - 'hs' => 'text/x-haskell', - 'htke' => 'application/vnd.kenameaapp', - 'htm' => 'text/html', - 'html' => 'text/html', - 'hvd' => 'application/vnd.yamaha.hv-dic', - 'hvp' => 'application/vnd.yamaha.hv-voice', - 'hvs' => 'application/vnd.yamaha.hv-script', - 'hwp' => 'application/x-hwp', - 'hwt' => 'application/x-hwt', - 'hxx' => 'text/x-c++hdr', - 'i2g' => 'application/vnd.intergeo', - 'ica' => 'application/x-ica', - 'icb' => 'image/x-tga', - 'icc' => 'application/vnd.iccprofile', - 'ice' => 'x-conference/x-cooltalk', - 'icm' => 'application/vnd.iccprofile', - 'icns' => 'image/x-icns', - 'ico' => 'image/x-icon', - 'ics' => 'text/calendar', - 'idl' => 'text/x-idl', - 'ief' => 'image/ief', - 'ifb' => 'text/calendar', - 'iff' => 'image/x-ilbm', - 'ifm' => 'application/vnd.shana.informed.formdata', - 'iges' => 'model/iges', - 'igl' => 'application/vnd.igloader', - 'igm' => 'application/vnd.insors.igm', - 'igs' => 'model/iges', - 'igx' => 'application/vnd.micrografx.igx', - 'iif' => 'application/vnd.shana.informed.interchange', - 'ilbm' => 'image/x-ilbm', - 'ime' => 'text/x-iMelody', - 'img' => 'application/x-raw-disk-image', - 'img.xz' => 'application/x-raw-disk-image-xz-compressed', - 'imp' => 'application/vnd.accpac.simply.imp', - 'ims' => 'application/vnd.ms-ims', - 'imy' => 'text/x-iMelody', - 'in' => 'text/plain', - 'ink' => 'application/inkml+xml', - 'inkml' => 'application/inkml+xml', - 'ins' => 'text/x-tex', - 'install' => 'application/x-install-instructions', - 'iota' => 'application/vnd.astraea-software.iota', - 'ipfix' => 'application/ipfix', - 'ipk' => 'application/vnd.shana.informed.package', - 'iptables' => 'text/x-iptables', - 'irm' => 'application/vnd.ibm.rights-management', - 'irp' => 'application/vnd.irepository.package+xml', - 'iso' => 'application/x-iso9660-image', - 'iso9660' => 'application/x-cd-image', - 'it' => 'audio/x-it', - 'it87' => 'application/x-it87', - 'itp' => 'application/vnd.shana.informed.formtemplate', - 'ivp' => 'application/vnd.immervision-ivp', - 'ivu' => 'application/vnd.immervision-ivu', - 'jad' => 'text/vnd.sun.j2me.app-descriptor', - 'jam' => 'application/vnd.jam', - 'jar' => 'application/java-archive', - 'java' => 'text/x-java-source', - 'jceks' => 'application/x-java-jce-keystore', - 'jisp' => 'application/vnd.jisp', - 'jks' => 'application/x-java-keystore', - 'jlt' => 'application/vnd.hp-jlyt', - 'jng' => 'image/x-jng', - 'jnlp' => 'application/x-java-jnlp-file', - 'joda' => 'application/vnd.joost.joda-archive', - 'jp2' => 'image/jp2', - 'jpg' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpf' => 'image/jp2', - 'jpe' => 'image/jpeg', - 'jpgm' => 'video/jpm', - 'jpgv' => 'video/jpeg', - 'jpm' => 'video/jpm', - 'jpr' => 'application/x-jbuilder-project', - 'jpx' => 'application/x-jbuilder-project', - 'js' => 'application/javascript', - 'jsm' => 'application/javascript', - 'json' => 'application/json', - 'jsonml' => 'application/jsonml+json', - 'k25' => 'image/x-kodak-k25', - 'kar' => 'audio/midi', - 'karbon' => 'application/vnd.kde.karbon', - 'kdc' => 'image/x-kodak-kdc', - 'kdelnk' => 'application/x-desktop', - 'kexi' => 'application/x-kexiproject-sqlite2', - 'kexic' => 'application/x-kexi-connectiondata', - 'kexis' => 'application/x-kexiproject-shortcut', - 'key' => 'application/x-iwork-keynote-sffkey', - 'kfo' => 'application/vnd.kde.kformula', - 'kia' => 'application/vnd.kidspiration', - 'kil' => 'application/x-killustrator', - 'kino' => 'application/smil', - 'kml' => 'application/vnd.google-earth.kml+xml', - 'kmz' => 'application/vnd.google-earth.kmz', - 'kne' => 'application/vnd.kinar', - 'knp' => 'application/vnd.kinar', - 'kon' => 'application/vnd.kde.kontour', - 'kpm' => 'application/x-kpovmodeler', - 'kpr' => 'application/vnd.kde.kpresenter', - 'kpt' => 'application/vnd.kde.kpresenter', - 'kpxx' => 'application/vnd.ds-keypoint', - 'kra' => 'application/x-krita', - 'ks' => 'application/x-java-keystore', - 'ksp' => 'application/vnd.kde.kspread', - 'ktr' => 'application/vnd.kahootz', - 'ktx' => 'image/ktx', - 'ktz' => 'application/vnd.kahootz', - 'kud' => 'application/x-kugar', - 'kwd' => 'application/vnd.kde.kword', - 'kwt' => 'application/vnd.kde.kword', - 'la' => 'application/x-shared-library-la', - 'lasxml' => 'application/vnd.las.las+xml', - 'latex' => 'application/x-latex', - 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', - 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', - 'lbm' => 'image/x-ilbm', - 'ldif' => 'text/x-ldif', - 'les' => 'application/vnd.hhe.lesson-player', - 'lha' => 'application/x-lzh-compressed', - 'lhs' => 'text/x-literate-haskell', - 'lhz' => 'application/x-lhz', - 'link66' => 'application/vnd.route66.link66+xml', - 'list' => 'text/plain', - 'list3820' => 'application/vnd.ibm.modcap', - 'listafp' => 'application/vnd.ibm.modcap', - 'lnk' => 'application/x-ms-shortcut', - 'log' => 'text/plain', - 'lostxml' => 'application/lost+xml', - 'lrf' => 'application/octet-stream', - 'lrm' => 'application/vnd.ms-lrm', - 'lrz' => 'application/x-lrzip', - 'ltf' => 'application/vnd.frogans.ltf', - 'ltx' => 'text/x-tex', - 'lua' => 'text/x-lua', - 'lvp' => 'audio/vnd.lucent.voice', - 'lwo' => 'image/x-lwo', - 'lwob' => 'image/x-lwo', - 'lwp' => 'application/vnd.lotus-wordpro', - 'lws' => 'image/x-lws', - 'ly' => 'text/x-lilypond', - 'lyx' => 'application/x-lyx', - 'lz' => 'application/x-lzip', - 'lz4' => 'application/x-lz4', - 'lzh' => 'application/x-lzh-compressed', - 'lzma' => 'application/x-lzma', - 'lzo' => 'application/x-lzop', - 'm' => 'text/x-objcsrc', - 'm13' => 'application/x-msmediaview', - 'm14' => 'application/x-msmediaview', - 'm15' => 'audio/x-mod', - 'm1u' => 'video/vnd.mpegurl', - 'm1v' => 'video/mpeg', - 'm21' => 'application/mp21', - 'm2a' => 'audio/mpeg', - 'm2t' => 'video/mp2t', - 'm2ts' => 'video/mp2t', - 'm2v' => 'video/mpeg', - 'm3a' => 'audio/mpeg', - 'm3u' => 'audio/x-mpegurl', - 'm3u8' => 'application/vnd.apple.mpegurl', - 'm4' => 'application/x-m4', - 'm4a' => 'audio/mp4', - 'm4b' => 'audio/x-m4b', - 'm4u' => 'video/vnd.mpegurl', - 'm4v' => 'video/x-m4v', - 'ma' => 'application/mathematica', - 'mab' => 'application/x-markaby', - 'mads' => 'application/mads+xml', - 'mag' => 'application/vnd.ecowin.chart', - 'mak' => 'text/x-makefile', - 'maker' => 'application/vnd.framemaker', - 'man' => 'text/troff', - 'manifest' => 'text/cache-manifest', - 'mar' => 'application/octet-stream', - 'markdown' => 'text/x-markdown', - 'mathml' => 'application/mathml+xml', - 'mb' => 'application/mathematica', - 'mbk' => 'application/vnd.mobius.mbk', - 'mbox' => 'application/mbox', - 'mc1' => 'application/vnd.medcalcdata', - 'mcd' => 'application/vnd.mcd', - 'mcurl' => 'text/vnd.curl.mcurl', - 'md' => 'text/x-markdown', - 'mdb' => 'application/x-msaccess', - 'mdi' => 'image/vnd.ms-modi', - 'me' => 'text/troff', - 'med' => 'audio/x-mod', - 'mesh' => 'model/mesh', - 'meta4' => 'application/metalink4+xml', - 'metalink' => 'application/metalink+xml', - 'mets' => 'application/mets+xml', - 'mfm' => 'application/vnd.mfmp', - 'mft' => 'application/rpki-manifest', - 'mgp' => 'application/vnd.osgeo.mapguide.package', - 'mgz' => 'application/vnd.proteus.magazine', - 'mht' => 'application/x-mimearchive', - 'mhtml' => 'application/x-mimearchive', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mie' => 'application/x-mie', - 'mif' => 'application/vnd.mif', - 'mime' => 'message/rfc822', - 'minipsf' => 'audio/x-minipsf', - 'mj2' => 'video/mj2', - 'mjp2' => 'video/mj2', - 'mk' => 'text/x-makefile', - 'mk3d' => 'video/x-matroska', - 'mka' => 'audio/x-matroska', - 'mkd' => 'text/x-markdown', - 'mks' => 'video/x-matroska', - 'mkv' => 'video/x-matroska', - 'ml' => 'text/x-ocaml', - 'mli' => 'text/x-ocaml', - 'mlp' => 'application/vnd.dolby.mlp', - 'mm' => 'text/x-troff-mm', - 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', - 'mmf' => 'application/vnd.smaf', - 'mml' => 'application/mathml+xml', - 'mmr' => 'image/vnd.fujixerox.edmics-mmr', - 'mng' => 'video/x-mng', - 'mny' => 'application/x-msmoney', - 'mo' => 'application/x-gettext-translation', - 'mo3' => 'audio/x-mo3', - 'mobi' => 'application/x-mobipocket-ebook', - 'moc' => 'text/x-moc', - 'mod' => 'audio/x-mod', - 'mods' => 'application/mods+xml', - 'mof' => 'text/x-mof', - 'moov' => 'video/quicktime', - 'mov' => 'video/quicktime', - 'movie' => 'video/x-sgi-movie', - 'mp+' => 'audio/x-musepack', - 'mp2' => 'audio/mpeg', - 'mp21' => 'application/mp21', - 'mp2a' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - 'mp4' => 'video/mp4', - 'mp4a' => 'audio/mp4', - 'mp4s' => 'application/mp4', - 'mp4v' => 'video/mp4', - 'mpc' => 'application/vnd.mophun.certificate', - 'mpe' => 'video/mpeg', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpg4' => 'video/mp4', - 'mpga' => 'audio/mpeg', - 'mpkg' => 'application/vnd.apple.installer+xml', - 'mpl' => 'video/mp2t', - 'mpls' => 'video/mp2t', - 'mpm' => 'application/vnd.blueice.multipass', - 'mpn' => 'application/vnd.mophun.application', - 'mpp' => 'application/vnd.ms-project', - 'mpt' => 'application/vnd.ms-project', - 'mpy' => 'application/vnd.ibm.minipay', - 'mqy' => 'application/vnd.mobius.mqy', - 'mrc' => 'application/marc', - 'mrcx' => 'application/marcxml+xml', - 'mrl' => 'text/x-mrml', - 'mrml' => 'text/x-mrml', - 'mrw' => 'image/x-minolta-mrw', - 'ms' => 'text/troff', - 'mscml' => 'application/mediaservercontrol+xml', - 'mseed' => 'application/vnd.fdsn.mseed', - 'mseq' => 'application/vnd.mseq', - 'msf' => 'application/vnd.epson.msf', - 'msh' => 'model/mesh', - 'msi' => 'application/x-msdownload', - 'msl' => 'application/vnd.mobius.msl', - 'msod' => 'image/x-msod', - 'msty' => 'application/vnd.muvee.style', - 'msx' => 'application/x-msx-rom', - 'mtm' => 'audio/x-mod', - 'mts' => 'model/vnd.mts', - 'mup' => 'text/x-mup', - 'mus' => 'application/vnd.musician', - 'musicxml' => 'application/vnd.recordare.musicxml+xml', - 'mvb' => 'application/x-msmediaview', - 'mwf' => 'application/vnd.mfer', - 'mxf' => 'application/mxf', - 'mxl' => 'application/vnd.recordare.musicxml', - 'mxml' => 'application/xv+xml', - 'mxs' => 'application/vnd.triscape.mxs', - 'mxu' => 'video/vnd.mpegurl', - 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', - 'n3' => 'text/n3', - 'n64' => 'application/x-n64-rom', - 'nb' => 'application/mathematica', - 'nbp' => 'application/vnd.wolfram.player', - 'nc' => 'application/x-netcdf', - 'ncx' => 'application/x-dtbncx+xml', - 'nds' => 'application/x-nintendo-ds-rom', - 'nef' => 'image/x-nikon-nef', - 'nes' => 'application/x-nes-rom', - 'nfo' => 'text/x-nfo', - 'ngdat' => 'application/vnd.nokia.n-gage.data', - 'nitf' => 'application/vnd.nitf', - 'nlu' => 'application/vnd.neurolanguage.nlu', - 'nml' => 'application/vnd.enliven', - 'nnd' => 'application/vnd.noblenet-directory', - 'nns' => 'application/vnd.noblenet-sealer', - 'nnw' => 'application/vnd.noblenet-web', - 'not' => 'text/x-mup', - 'npx' => 'image/vnd.net-fpx', - 'nsc' => 'application/x-conference', - 'nsf' => 'application/vnd.lotus-notes', - 'nsv' => 'video/x-nsv', - 'ntf' => 'application/vnd.nitf', - 'nzb' => 'application/x-nzb', - 'o' => 'application/x-object', - 'oa2' => 'application/vnd.fujitsu.oasys2', - 'oa3' => 'application/vnd.fujitsu.oasys3', - 'oas' => 'application/vnd.fujitsu.oasys', - 'obd' => 'application/x-msbinder', - 'obj' => 'application/x-tgif', - 'ocl' => 'text/x-ocl', - 'oda' => 'application/oda', - 'odb' => 'application/vnd.oasis.opendocument.database', - 'odc' => 'application/vnd.oasis.opendocument.chart', - 'odf' => 'application/vnd.oasis.opendocument.formula', - 'odft' => 'application/vnd.oasis.opendocument.formula-template', - 'odg' => 'application/vnd.oasis.opendocument.graphics', - 'odi' => 'application/vnd.oasis.opendocument.image', - 'odm' => 'application/vnd.oasis.opendocument.text-master', - 'odp' => 'application/vnd.oasis.opendocument.presentation', - 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', - 'odt' => 'application/vnd.oasis.opendocument.text', - 'oga' => 'audio/ogg', - 'ogg' => 'audio/ogg', - 'ogm' => 'video/x-ogm+ogg', - 'ogv' => 'video/ogg', - 'ogx' => 'application/ogg', - 'old' => 'application/x-trash', - 'oleo' => 'application/x-oleo', - 'omdoc' => 'application/omdoc+xml', - 'onepkg' => 'application/onenote', - 'onetmp' => 'application/onenote', - 'onetoc' => 'application/onenote', - 'onetoc2' => 'application/onenote', - 'ooc' => 'text/x-ooc', - 'oot' => 'application/vnd.oasis.opendocument.text', - 'opf' => 'application/oebps-package+xml', - 'opml' => 'text/x-opml', - 'oprc' => 'application/vnd.palm', - 'opus' => 'audio/ogg', - 'ora' => 'image/openraster', - 'orf' => 'image/x-olympus-orf', - 'org' => 'application/vnd.lotus-organizer', - 'osf' => 'application/vnd.yamaha.openscoreformat', - 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', - 'otc' => 'application/vnd.oasis.opendocument.chart-template', - 'otf' => 'application/x-font-otf', - 'otg' => 'application/vnd.oasis.opendocument.graphics-template', - 'oth' => 'application/vnd.oasis.opendocument.text-web', - 'oti' => 'application/vnd.oasis.opendocument.image-template', - 'otp' => 'application/vnd.oasis.opendocument.presentation-template', - 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', - 'ott' => 'application/vnd.oasis.opendocument.text-template', - 'owl' => 'application/rdf+xml', - 'oxps' => 'application/oxps', - 'oxt' => 'application/vnd.openofficeorg.extension', - 'p' => 'text/x-pascal', - 'p10' => 'application/pkcs10', - 'p12' => 'application/x-pkcs12', - 'p7b' => 'application/x-pkcs7-certificates', - 'p7c' => 'application/pkcs7-mime', - 'p7m' => 'application/pkcs7-mime', - 'p7r' => 'application/x-pkcs7-certreqresp', - 'p7s' => 'application/pkcs7-signature', - 'p8' => 'application/pkcs8', - 'pack' => 'application/x-java-pack200', - 'pak' => 'application/x-pak', - 'par2' => 'application/x-par2', - 'pas' => 'text/x-pascal', - 'patch' => 'text/diff', - 'paw' => 'application/vnd.pawaafile', - 'pbd' => 'application/vnd.powerbuilder6', - 'pbm' => 'image/x-portable-bitmap', - 'pcap' => 'application/vnd.tcpdump.pcap', - 'pcd' => 'image/x-photo-cd', - 'pce' => 'application/x-pc-engine-rom', - 'pcf' => 'application/x-font-pcf', - 'pcf.gz' => 'application/x-font-pcf', - 'pcf.z' => 'application/x-font-pcf', - 'pcl' => 'application/vnd.hp-pcl', - 'pclxl' => 'application/vnd.hp-pclxl', - 'pct' => 'image/x-pict', - 'pcurl' => 'application/vnd.curl.pcurl', - 'pcx' => 'image/x-pcx', - 'pdb' => 'application/vnd.palm', - 'pdc' => 'application/x-aportisdoc', - 'pdf' => 'application/pdf', - 'pdf.bz2' => 'application/x-bzpdf', - 'pdf.gz' => 'application/x-gzpdf', - 'pdf.xz' => 'application/x-xzpdf', - 'pef' => 'image/x-pentax-pef', - 'pem' => 'application/x-x509-ca-cert', - 'perl' => 'application/x-perl', - 'pfa' => 'application/x-font-type1', - 'pfb' => 'application/x-font-type1', - 'pfm' => 'application/x-font-type1', - 'pfr' => 'application/font-tdpfr', - 'pfx' => 'application/x-pkcs12', - 'pgm' => 'image/x-portable-graymap', - 'pgn' => 'application/x-chess-pgn', - 'pgp' => 'application/pgp-encrypted', - 'php' => 'application/x-httpd-php', - 'php3' => 'application/x-httpd-php3', - 'php4' => 'application/x-php', - 'php5' => 'application/x-php', - 'phps' => 'application/x-php', - 'pic' => 'image/x-pict', - 'pict' => 'image/x-pict', - 'pict1' => 'image/x-pict', - 'pict2' => 'image/x-pict', - 'pk' => 'application/x-tex-pk', - 'pkg' => 'application/octet-stream', - 'pki' => 'application/pkixcmp', - 'pkipath' => 'application/pkix-pkipath', - 'pkr' => 'application/pgp-keys', - 'pl' => 'application/x-perl', - 'pla' => 'audio/x-iriver-pla', - 'plb' => 'application/vnd.3gpp.pic-bw-large', - 'plc' => 'application/vnd.mobius.plc', - 'plf' => 'application/vnd.pocketlearn', - 'pln' => 'application/x-planperfect', - 'pls' => 'application/pls+xml', - 'pm' => 'application/x-perl', - 'pml' => 'application/vnd.ctc-posml', - 'png' => 'image/png', - 'pnm' => 'image/x-portable-anymap', - 'pntg' => 'image/x-macpaint', - 'po' => 'text/plain', - 'pod' => 'application/x-perl', - 'por' => 'application/x-spss-por', - 'portpkg' => 'application/vnd.macports.portpkg', - 'pot' => 'application/vnd.ms-powerpoint', - 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', - 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', - 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', - 'ppd' => 'application/vnd.cups-ppd', - 'ppm' => 'image/x-portable-pixmap', - 'pps' => 'application/vnd.ms-powerpoint', - 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', - 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', - 'ppt' => 'application/vnd.ms-powerpoint', - 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', - 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', - 'ppz' => 'application/vnd.ms-powerpoint', - 'pqa' => 'application/vnd.palm', - 'prc' => 'application/x-mobipocket-ebook', - 'pre' => 'application/vnd.lotus-freelance', - 'prf' => 'application/pics-rules', - 'ps' => 'application/postscript', - 'ps.bz2' => 'application/x-bzpostscript', - 'ps.gz' => 'application/x-gzpostscript', - 'psb' => 'application/vnd.3gpp.pic-bw-small', - 'psd' => 'image/vnd.adobe.photoshop', - 'psf' => 'application/x-font-linux-psf', - 'psf.gz' => 'application/x-gz-font-linux-psf', - 'psflib' => 'audio/x-psflib', - 'psid' => 'audio/prs.sid', - 'pskcxml' => 'application/pskc+xml', - 'psw' => 'application/x-pocket-word', - 'ptid' => 'application/vnd.pvi.ptid1', - 'pub' => 'application/x-mspublisher', - 'pvb' => 'application/vnd.3gpp.pic-bw-var', - 'pw' => 'application/x-pw', - 'pwn' => 'application/vnd.3m.post-it-notes', - 'py' => 'text/x-python', - 'pya' => 'audio/vnd.ms-playready.media.pya', - 'pyc' => 'application/x-python-bytecode', - 'pyo' => 'application/x-python-bytecode', - 'pyv' => 'video/vnd.ms-playready.media.pyv', - 'pyx' => 'text/x-python', - 'qam' => 'application/vnd.epson.quickanime', - 'qbo' => 'application/vnd.intu.qbo', - 'qfx' => 'application/vnd.intu.qfx', - 'qif' => 'application/x-qw', - 'qml' => 'text/x-qml', - 'qps' => 'application/vnd.publishare-delta-tree', - 'qt' => 'video/quicktime', - 'qti' => 'application/x-qtiplot', - 'qti.gz' => 'application/x-qtiplot', - 'qtif' => 'image/x-quicktime', - 'qtl' => 'application/x-quicktime-media-link', - 'qtvr' => 'video/quicktime', - 'qwd' => 'application/vnd.quark.quarkxpress', - 'qwt' => 'application/vnd.quark.quarkxpress', - 'qxb' => 'application/vnd.quark.quarkxpress', - 'qxd' => 'application/vnd.quark.quarkxpress', - 'qxl' => 'application/vnd.quark.quarkxpress', - 'qxt' => 'application/vnd.quark.quarkxpress', - 'ra' => 'audio/x-pn-realaudio', - 'raf' => 'image/x-fuji-raf', - 'ram' => 'audio/x-pn-realaudio', - 'rar' => 'application/x-rar-compressed', - 'ras' => 'image/x-cmu-raster', - 'raw' => 'image/x-panasonic-raw', - 'raw-disk-image' => 'application/x-raw-disk-image', - 'raw-disk-image.xz' => 'application/x-raw-disk-image-xz-compressed', - 'rax' => 'audio/vnd.rn-realaudio', - 'rb' => 'application/x-ruby', - 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', - 'rdf' => 'application/rdf+xml', - 'rdfs' => 'application/rdf+xml', - 'rdz' => 'application/vnd.data-vision.rdz', - 'reg' => 'text/x-ms-regedit', - 'rej' => 'text/x-reject', - 'rep' => 'application/vnd.businessobjects', - 'res' => 'application/x-dtbresource+xml', - 'rgb' => 'image/x-rgb', - 'rif' => 'application/reginfo+xml', - 'rip' => 'audio/vnd.rip', - 'ris' => 'application/x-research-info-systems', - 'rl' => 'application/resource-lists+xml', - 'rlc' => 'image/vnd.fujixerox.edmics-rlc', - 'rld' => 'application/resource-lists-diff+xml', - 'rle' => 'image/rle', - 'rm' => 'application/vnd.rn-realmedia', - 'rmi' => 'audio/midi', - 'rmj' => 'application/vnd.rn-realmedia', - 'rmm' => 'application/vnd.rn-realmedia', - 'rmp' => 'audio/x-pn-realaudio-plugin', - 'rms' => 'application/vnd.jcp.javame.midlet-rms', - 'rmvb' => 'application/vnd.rn-realmedia-vbr', - 'rmx' => 'application/vnd.rn-realmedia', - 'rnc' => 'application/relax-ng-compact-syntax', - 'rng' => 'application/xml', - 'roa' => 'application/rpki-roa', - 'roff' => 'text/troff', - 'rp' => 'image/vnd.rn-realpix', - 'rp9' => 'application/vnd.cloanto.rp9', - 'rpm' => 'application/x-rpm', - 'rpss' => 'application/vnd.nokia.radio-presets', - 'rpst' => 'application/vnd.nokia.radio-preset', - 'rq' => 'application/sparql-query', - 'rs' => 'application/rls-services+xml', - 'rsd' => 'application/rsd+xml', - 'rss' => 'application/rss+xml', - 'rt' => 'text/vnd.rn-realtext', - 'rtf' => 'application/rtf', - 'rtx' => 'text/richtext', - 'rv' => 'video/vnd.rn-realvideo', - 'rvx' => 'video/vnd.rn-realvideo', - 'rw2' => 'image/x-panasonic-raw2', - 's' => 'text/x-asm', - 's3m' => 'audio/s3m', - 'saf' => 'application/vnd.yamaha.smaf-audio', - 'sam' => 'application/x-amipro', - 'sami' => 'application/x-sami', - 'sav' => 'application/x-spss-sav', - 'sbml' => 'application/sbml+xml', - 'sc' => 'application/vnd.ibm.secure-container', - 'scala' => 'text/x-scala', - 'scd' => 'application/x-msschedule', - 'scm' => 'application/vnd.lotus-screencam', - 'scq' => 'application/scvp-cv-request', - 'scs' => 'application/scvp-cv-response', - 'scurl' => 'text/vnd.curl.scurl', - 'sda' => 'application/vnd.stardivision.draw', - 'sdc' => 'application/vnd.stardivision.calc', - 'sdd' => 'application/vnd.stardivision.impress', - 'sdkd' => 'application/vnd.solent.sdkm+xml', - 'sdkm' => 'application/vnd.solent.sdkm+xml', - 'sdp' => 'application/sdp', - 'sds' => 'application/vnd.stardivision.chart', - 'sdw' => 'application/vnd.stardivision.writer', - 'see' => 'application/vnd.seemail', - 'seed' => 'application/vnd.fdsn.seed', - 'sema' => 'application/vnd.sema', - 'semd' => 'application/vnd.semd', - 'semf' => 'application/vnd.semf', - 'ser' => 'application/java-serialized-object', - 'setpay' => 'application/set-payment-initiation', - 'setreg' => 'application/set-registration-initiation', - 'sfc' => 'application/vnd.nintendo.snes.rom', - 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', - 'sfs' => 'application/vnd.spotfire.sfs', - 'sfv' => 'text/x-sfv', - 'sgf' => 'application/x-go-sgf', - 'sgi' => 'image/sgi', - 'sgl' => 'application/vnd.stardivision.writer-global', - 'sgm' => 'text/sgml', - 'sgml' => 'text/sgml', - 'sh' => 'application/x-sh', - 'shape' => 'application/x-dia-shape', - 'shar' => 'application/x-shar', - 'shf' => 'application/shf+xml', - 'shn' => 'application/x-shorten', - 'shtml' => 'text/html', - 'siag' => 'application/x-siag', - 'sid' => 'image/x-mrsid-image', - 'sig' => 'application/pgp-signature', - 'sik' => 'application/x-trash', - 'sil' => 'audio/silk', - 'silo' => 'model/mesh', - 'sis' => 'application/vnd.symbian.install', - 'sisx' => 'application/vnd.symbian.install', - 'sit' => 'application/x-stuffit', - 'sitx' => 'application/x-stuffitx', - 'siv' => 'application/sieve', - 'sk' => 'image/x-skencil', - 'sk1' => 'image/x-skencil', - 'skd' => 'application/vnd.koan', - 'skm' => 'application/vnd.koan', - 'skp' => 'application/vnd.koan', - 'skr' => 'application/pgp-keys', - 'skt' => 'application/vnd.koan', - 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', - 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', - 'slk' => 'text/spreadsheet', - 'slt' => 'application/vnd.epson.salt', - 'sm' => 'application/vnd.stepmania.stepchart', - 'smaf' => 'application/x-smaf', - 'smc' => 'application/vnd.nintendo.snes.rom', - 'smd' => 'application/vnd.stardivision.mail', - 'smf' => 'application/vnd.stardivision.math', - 'smi' => 'application/smil+xml', - 'smil' => 'application/smil+xml', - 'sml' => 'application/smil', - 'sms' => 'application/x-sms-rom', - 'smv' => 'video/x-smv', - 'smzip' => 'application/vnd.stepmania.package', - 'snd' => 'audio/basic', - 'snf' => 'application/x-font-snf', - 'so' => 'application/octet-stream', - 'spc' => 'application/x-pkcs7-certificates', - 'spd' => 'application/x-font-speedo', - 'spec' => 'text/x-rpm-spec', - 'spf' => 'application/vnd.yamaha.smaf-phrase', - 'spl' => 'application/x-futuresplash', - 'spm' => 'application/x-source-rpm', - 'spot' => 'text/vnd.in3d.spot', - 'spp' => 'application/scvp-vp-response', - 'spq' => 'application/scvp-vp-request', - 'spx' => 'audio/ogg', - 'sql' => 'application/x-sql', - 'sr2' => 'image/x-sony-sr2', - 'src' => 'application/x-wais-source', - 'src.rpm' => 'application/x-source-rpm', - 'srf' => 'image/x-sony-srf', - 'srt' => 'application/x-subrip', - 'sru' => 'application/sru+xml', - 'srx' => 'application/sparql-results+xml', - 'ss' => 'text/x-scheme', - 'ssa' => 'text/x-ssa', - 'ssdl' => 'application/ssdl+xml', - 'sse' => 'application/vnd.kodak-descriptor', - 'ssf' => 'application/vnd.epson.ssf', - 'ssml' => 'application/ssml+xml', - 'st' => 'application/vnd.sailingtracker.track', - 'stc' => 'application/vnd.sun.xml.calc.template', - 'std' => 'application/vnd.sun.xml.draw.template', - 'stf' => 'application/vnd.wt.stf', - 'sti' => 'application/vnd.sun.xml.impress.template', - 'stk' => 'application/hyperstudio', - 'stl' => 'application/vnd.ms-pki.stl', - 'stm' => 'audio/x-stm', - 'str' => 'application/vnd.pg.format', - 'stw' => 'application/vnd.sun.xml.writer.template', - 'sty' => 'text/x-tex', - 'sub' => 'text/vnd.dvb.subtitle', - 'sun' => 'image/x-sun-raster', - 'sus' => 'application/vnd.sus-calendar', - 'susp' => 'application/vnd.sus-calendar', - 'sv' => 'text/x-svsrc', - 'sv4cpio' => 'application/x-sv4cpio', - 'sv4crc' => 'application/x-sv4crc', - 'svc' => 'application/vnd.dvb.service', - 'svd' => 'application/vnd.svd', - 'svg' => 'image/svg+xml', - 'svgz' => 'image/svg+xml', - 'svh' => 'text/x-svhdr', - 'swa' => 'application/x-director', - 'swf' => 'application/x-shockwave-flash', - 'swi' => 'application/vnd.aristanetworks.swi', - 'swm' => 'application/x-ms-wim', - 'sxc' => 'application/vnd.sun.xml.calc', - 'sxd' => 'application/vnd.sun.xml.draw', - 'sxg' => 'application/vnd.sun.xml.writer.global', - 'sxi' => 'application/vnd.sun.xml.impress', - 'sxm' => 'application/vnd.sun.xml.math', - 'sxw' => 'application/vnd.sun.xml.writer', - 'sylk' => 'text/spreadsheet', - 't' => 'text/troff', - 't2t' => 'text/x-txt2tags', - 't3' => 'application/x-t3vm-image', - 'taglet' => 'application/vnd.mynfc', - 'tao' => 'application/vnd.tao.intent-module-archive', - 'tar' => 'application/x-tar', - 'tar.bz' => 'application/x-bzip-compressed-tar', - 'tar.bz2' => 'application/x-bzip-compressed-tar', - 'tar.gz' => 'application/x-compressed-tar', - 'tar.lrz' => 'application/x-lrzip-compressed-tar', - 'tar.lzma' => 'application/x-lzma-compressed-tar', - 'tar.lzo' => 'application/x-tzo', - 'tar.xz' => 'application/x-xz-compressed-tar', - 'tar.z' => 'application/x-tarz', - 'taz' => 'application/x-tarz', - 'tb2' => 'application/x-bzip-compressed-tar', - 'tbz' => 'application/x-bzip-compressed-tar', - 'tbz2' => 'application/x-bzip-compressed-tar', - 'tcap' => 'application/vnd.3gpp2.tcap', - 'tcl' => 'application/x-tcl', - 'teacher' => 'application/vnd.smart.teacher', - 'tei' => 'application/tei+xml', - 'teicorpus' => 'application/tei+xml', - 'tex' => 'application/x-tex', - 'texi' => 'application/x-texinfo', - 'texinfo' => 'application/x-texinfo', - 'text' => 'text/plain', - 'tfi' => 'application/thraud+xml', - 'tfm' => 'application/x-tex-tfm', - 'tga' => 'image/x-tga', - 'tgz' => 'application/x-gtar', - 'theme' => 'application/x-theme', - 'themepack' => 'application/x-windows-themepack', - 'thmx' => 'application/vnd.ms-officetheme', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'tk' => 'text/x-tcl', - 'tlrz' => 'application/x-lrzip-compressed-tar', - 'tlz' => 'application/x-lzma-compressed-tar', - 'tmo' => 'application/vnd.tmobile-livetv', - 'tnef' => 'application/vnd.ms-tnef', - 'tnf' => 'application/vnd.ms-tnef', - 'toc' => 'application/x-cdrdao-toc', - 'torrent' => 'application/x-bittorrent', - 'tpic' => 'image/x-tga', - 'tpl' => 'application/vnd.groove-tool-template', - 'tpt' => 'application/vnd.trid.tpt', - 'tr' => 'text/troff', - 'tra' => 'application/vnd.trueapp', - 'trig' => 'application/x-trig', - 'trm' => 'application/x-msterminal', - 'ts' => 'text/vnd.trolltech.linguist', - 'tsd' => 'application/timestamped-data', - 'tsv' => 'text/tab-separated-values', - 'tta' => 'audio/x-tta', - 'ttc' => 'application/x-font-ttf', - 'ttf' => 'application/x-font-ttf', - 'ttl' => 'text/turtle', - 'ttx' => 'application/x-font-ttx', - 'twd' => 'application/vnd.simtech-mindmapper', - 'twds' => 'application/vnd.simtech-mindmapper', - 'txd' => 'application/vnd.genomatix.tuxedo', - 'txf' => 'application/vnd.mobius.txf', - 'txt' => 'text/plain', - 'txz' => 'application/x-xz-compressed-tar', - 'tzo' => 'application/x-tzo', - 'u32' => 'application/x-authorware-bin', - 'udeb' => 'application/x-debian-package', - 'ufd' => 'application/vnd.ufdl', - 'ufdl' => 'application/vnd.ufdl', - 'ufraw' => 'application/x-ufraw', - 'ui' => 'application/x-designer', - 'uil' => 'text/x-uil', - 'ult' => 'audio/x-mod', - 'ulx' => 'application/x-glulx', - 'umj' => 'application/vnd.umajin', - 'uni' => 'audio/x-mod', - 'unityweb' => 'application/vnd.unity', - 'uoml' => 'application/vnd.uoml+xml', - 'uri' => 'text/uri-list', - 'uris' => 'text/uri-list', - 'url' => 'application/x-mswinurl', - 'urls' => 'text/uri-list', - 'ustar' => 'application/x-ustar', - 'utz' => 'application/vnd.uiq.theme', - 'uu' => 'text/x-uuencode', - 'uue' => 'text/x-uuencode', - 'uva' => 'audio/vnd.dece.audio', - 'uvd' => 'application/vnd.dece.data', - 'uvf' => 'application/vnd.dece.data', - 'uvg' => 'image/vnd.dece.graphic', - 'uvh' => 'video/vnd.dece.hd', - 'uvi' => 'image/vnd.dece.graphic', - 'uvm' => 'video/vnd.dece.mobile', - 'uvp' => 'video/vnd.dece.pd', - 'uvs' => 'video/vnd.dece.sd', - 'uvt' => 'application/vnd.dece.ttml+xml', - 'uvu' => 'video/vnd.uvvu.mp4', - 'uvv' => 'video/vnd.dece.video', - 'uvva' => 'audio/vnd.dece.audio', - 'uvvd' => 'application/vnd.dece.data', - 'uvvf' => 'application/vnd.dece.data', - 'uvvg' => 'image/vnd.dece.graphic', - 'uvvh' => 'video/vnd.dece.hd', - 'uvvi' => 'image/vnd.dece.graphic', - 'uvvm' => 'video/vnd.dece.mobile', - 'uvvp' => 'video/vnd.dece.pd', - 'uvvs' => 'video/vnd.dece.sd', - 'uvvt' => 'application/vnd.dece.ttml+xml', - 'uvvu' => 'video/vnd.uvvu.mp4', - 'uvvv' => 'video/vnd.dece.video', - 'uvvx' => 'application/vnd.dece.unspecified', - 'uvvz' => 'application/vnd.dece.zip', - 'uvx' => 'application/vnd.dece.unspecified', - 'uvz' => 'application/vnd.dece.zip', - 'v' => 'text/x-verilog', - 'vala' => 'text/x-vala', - 'vapi' => 'text/x-vala', - 'vcard' => 'text/vcard', - 'vcd' => 'application/x-cdlink', - 'vcf' => 'text/x-vcard', - 'vcg' => 'application/vnd.groove-vcard', - 'vcs' => 'text/calendar', - 'vct' => 'text/vcard', - 'vcx' => 'application/vnd.vcx', - 'vda' => 'image/x-tga', - 'vfb' => 'text/calendar', - 'vhd' => 'text/x-vhdl', - 'vhdl' => 'text/x-vhdl', - 'vis' => 'application/vnd.visionary', - 'viv' => 'video/vnd.vivo', - 'vivo' => 'video/vivo', - 'vlc' => 'audio/x-mpegurl', - 'vob' => 'video/x-ms-vob', - 'voc' => 'audio/x-voc', - 'vor' => 'application/vnd.stardivision.writer', - 'vox' => 'application/x-authorware-bin', - 'vrm' => 'model/vrml', - 'vrml' => 'model/vrml', - 'vsd' => 'application/vnd.visio', - 'vsf' => 'application/vnd.vsf', - 'vss' => 'application/vnd.visio', - 'vst' => 'application/vnd.visio', - 'vsw' => 'application/vnd.visio', - 'vtt' => 'text/vtt', - 'vtu' => 'model/vnd.vtu', - 'vxml' => 'application/voicexml+xml', - 'w3d' => 'application/x-director', - 'wad' => 'application/x-doom', - 'wav' => 'audio/x-wav', - 'wax' => 'audio/x-ms-wax', - 'wb1' => 'application/x-quattropro', - 'wb2' => 'application/x-quattropro', - 'wb3' => 'application/x-quattropro', - 'wbmp' => 'image/vnd.wap.wbmp', - 'wbs' => 'application/vnd.criticaltools.wbs+xml', - 'wbxml' => 'application/vnd.wap.wbxml', - 'wcm' => 'application/vnd.ms-works', - 'wdb' => 'application/vnd.ms-works', - 'wdp' => 'image/vnd.ms-photo', - 'weba' => 'audio/webm', - 'webm' => 'video/webm', - 'webp' => 'image/webp', - 'wg' => 'application/vnd.pmi.widget', - 'wgt' => 'application/widget', - 'wim' => 'application/x-ms-wim', - 'wk1' => 'application/vnd.lotus-1-2-3', - 'wk3' => 'application/vnd.lotus-1-2-3', - 'wk4' => 'application/vnd.lotus-1-2-3', - 'wks' => 'application/vnd.ms-works', - 'wm' => 'video/x-ms-wm', - 'wma' => 'audio/x-ms-wma', - 'wmd' => 'application/x-ms-wmd', - 'wmf' => 'application/x-msmetafile', - 'wml' => 'text/vnd.wap.wml', - 'wmlc' => 'application/vnd.wap.wmlc', - 'wmls' => 'text/vnd.wap.wmlscript', - 'wmlsc' => 'application/vnd.wap.wmlscriptc', - 'wmv' => 'video/x-ms-wmv', - 'wmx' => 'video/x-ms-wmx', - 'wmz' => 'application/x-ms-wmz', - 'woff' => 'application/font-woff', - 'wp' => 'application/vnd.wordperfect', - 'wp4' => 'application/vnd.wordperfect', - 'wp5' => 'application/vnd.wordperfect', - 'wp6' => 'application/vnd.wordperfect', - 'wpd' => 'application/vnd.wordperfect', - 'wpg' => 'application/x-wpg', - 'wpl' => 'application/vnd.ms-wpl', - 'wpp' => 'application/vnd.wordperfect', - 'wps' => 'application/vnd.ms-works', - 'wqd' => 'application/vnd.wqd', - 'wri' => 'application/x-mswrite', - 'wrl' => 'model/vrml', - 'wsdl' => 'application/wsdl+xml', - 'wsgi' => 'text/x-python', - 'wspolicy' => 'application/wspolicy+xml', - 'wtb' => 'application/vnd.webturbo', - 'wv' => 'audio/x-wavpack', - 'wvc' => 'audio/x-wavpack-correction', - 'wvp' => 'audio/x-wavpack', - 'wvx' => 'video/x-ms-wvx', - 'wwf' => 'application/x-wwf', - 'x32' => 'application/x-authorware-bin', - 'x3d' => 'model/x3d+xml', - 'x3db' => 'model/x3d+binary', - 'x3dbz' => 'model/x3d+binary', - 'x3dv' => 'model/x3d+vrml', - 'x3dvz' => 'model/x3d+vrml', - 'x3dz' => 'model/x3d+xml', - 'x3f' => 'image/x-sigma-x3f', - 'xac' => 'application/x-gnucash', - 'xaml' => 'application/xaml+xml', - 'xap' => 'application/x-silverlight-app', - 'xar' => 'application/vnd.xara', - 'xbap' => 'application/x-ms-xbap', - 'xbd' => 'application/vnd.fujixerox.docuworks.binder', - 'xbel' => 'application/x-xbel', - 'xbl' => 'application/xml', - 'xbm' => 'image/x-xbitmap', - 'xcf' => 'image/x-xcf', - 'xcf.bz2' => 'image/x-compressed-xcf', - 'xcf.gz' => 'image/x-compressed-xcf', - 'xdf' => 'application/xcap-diff+xml', - 'xdm' => 'application/vnd.syncml.dm+xml', - 'xdp' => 'application/vnd.adobe.xdp+xml', - 'xdssc' => 'application/dssc+xml', - 'xdw' => 'application/vnd.fujixerox.docuworks', - 'xenc' => 'application/xenc+xml', - 'xer' => 'application/patch-ops-error+xml', - 'xfdf' => 'application/vnd.adobe.xfdf', - 'xfdl' => 'application/vnd.xfdl', - 'xht' => 'application/xhtml+xml', - 'xhtml' => 'application/xhtml+xml', - 'xhvml' => 'application/xv+xml', - 'xi' => 'audio/x-xi', - 'xif' => 'image/vnd.xiff', - 'xla' => 'application/vnd.ms-excel', - 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', - 'xlc' => 'application/vnd.ms-excel', - 'xld' => 'application/vnd.ms-excel', - 'xlf' => 'application/x-xliff+xml', - 'xliff' => 'application/x-xliff', - 'xll' => 'application/vnd.ms-excel', - 'xlm' => 'application/vnd.ms-excel', - 'xlr' => 'application/vnd.ms-works', - 'xls' => 'application/vnd.ms-excel', - 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', - 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'xlt' => 'application/vnd.ms-excel', - 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', - 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', - 'xlw' => 'application/vnd.ms-excel', - 'xm' => 'audio/xm', - 'xmf' => 'audio/x-xmf', - 'xmi' => 'text/x-xmi', - 'xml' => 'application/xml', - 'xo' => 'application/vnd.olpc-sugar', - 'xop' => 'application/xop+xml', - 'xpi' => 'application/x-xpinstall', - 'xpl' => 'application/xproc+xml', - 'xpm' => 'image/x-xpixmap', - 'xpr' => 'application/vnd.is-xpr', - 'xps' => 'application/vnd.ms-xpsdocument', - 'xpw' => 'application/vnd.intercon.formnet', - 'xpx' => 'application/vnd.intercon.formnet', - 'xsd' => 'application/xml', - 'xsl' => 'application/xml', - 'xslfo' => 'text/x-xslfo', - 'xslt' => 'application/xslt+xml', - 'xsm' => 'application/vnd.syncml+xml', - 'xspf' => 'application/xspf+xml', - 'xul' => 'application/vnd.mozilla.xul+xml', - 'xvm' => 'application/xv+xml', - 'xvml' => 'application/xv+xml', - 'xwd' => 'image/x-xwindowdump', - 'xyz' => 'chemical/x-xyz', - 'xz' => 'application/x-xz', - 'yaml' => 'application/x-yaml', - 'yang' => 'application/yang', - 'yin' => 'application/yin+xml', - 'yml' => 'application/x-yaml', - 'z' => 'application/x-compress', - 'z1' => 'application/x-zmachine', - 'z2' => 'application/x-zmachine', - 'z3' => 'application/x-zmachine', - 'z4' => 'application/x-zmachine', - 'z5' => 'application/x-zmachine', - 'z6' => 'application/x-zmachine', - 'z7' => 'application/x-zmachine', - 'z8' => 'application/x-zmachine', - 'zabw' => 'application/x-abiword', - 'zaz' => 'application/vnd.zzazz.deck+xml', - 'zip' => 'application/zip', - 'zir' => 'application/vnd.zul', - 'zirz' => 'application/vnd.zul', - 'zmm' => 'application/vnd.handheld-entertainment+xml', - 'zoo' => 'application/x-zoo', - 'zsav' => 'application/x-spss-sav', - '123' => 'application/vnd.lotus-1-2-3', - '602' => 'application/x-t602', - '669' => 'audio/x-mod' -); \ No newline at end of file diff --git a/lib/horde/framework/Horde/Secret.php b/lib/horde/framework/Horde/Secret.php deleted file mode 100644 index ab86ef3c2ab..00000000000 --- a/lib/horde/framework/Horde/Secret.php +++ /dev/null @@ -1,224 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL - * @package Secret - */ -class Horde_Secret -{ - /** Generic, default keyname. */ - const DEFAULT_KEY = 'generic'; - - /** - * Configuration parameters. - * - * @var array - */ - protected $_params = array( - 'cookie_domain' => '', - 'cookie_path' => '', - 'cookie_ssl' => false, - 'session_name' => 'horde_secret' - ); - - /** - * Cipher cache. - * - * @var array - */ - protected $_cipherCache = array(); - - /** - * Key cache. - * - * @var array - */ - protected $_keyCache = array(); - - /** - * Constructor. - * - * @param array $params Configuration parameters: - * - cookie_domain: (string) The cookie domain. - * - cookie_path: (string) The cookie path. - * - cookie_ssl: (boolean) Only transmit cookie securely? - * - session_name: (string) The cookie session name. - */ - public function __construct($params = array()) - { - $this->_params = array_merge($this->_params, $params); - } - - /** - * Take a small piece of data and encrypt it with a key. - * - * @param string $key The key to use for encryption. - * @param string $message The plaintext message. - * - * @return string The ciphertext message. - * @throws Horde_Secret_Exception - */ - public function write($key, $message) - { - $message = strval($message); - return (strlen($key) && strlen($message)) - ? $this->_getCipherOb($key)->encrypt($message) - : ''; - } - - /** - * Decrypt a message encrypted with write(). - * - * @param string $key The key to use for decryption. - * @param string $message The ciphertext message. - * - * @return string The plaintext message. - * @throws Horde_Secret_Exception - */ - public function read($key, $ciphertext) - { - $ciphertext = strval($ciphertext); - return (strlen($key) && strlen($ciphertext)) - ? $this->_getCipherOb($key)->decrypt($ciphertext) - : ''; - } - - /** - * Returns the cached crypt object. - * - * @param string $key The key to use for [de|en]cryption. Only the first - * 56 bytes of this string is used. - * - * @return Horde_Crypt_Blowfish The crypt object. - * @throws Horde_Secret_Exception - */ - protected function _getCipherOb($key) - { - if (!is_string($key)) { - throw new Horde_Secret_Exception('Key must be a string', Horde_Secret_Exception::KEY_NOT_STRING); - } - - if (!strlen($key)) { - throw new Horde_Secret_Exception('Key must be non-zero.', Horde_Secret_Exception::KEY_ZERO_LENGTH); - } - - $key = substr($key, 0, 56); - - $idx = hash('md5', $key); - if (!isset($this->_cipherCache[$idx])) { - $this->_cipherCache[$idx] = new Horde_Crypt_Blowfish($key); - } - - return $this->_cipherCache[$idx]; - } - - /** - * Generate a secret key (for encryption), either using a random - * string and storing it in a cookie if the user has cookies - * enabled, or munging some known values if they don't. - * - * @param string $keyname The name of the key to set. - * - * @return string The secret key that has been generated. - */ - public function setKey($keyname = self::DEFAULT_KEY) - { - $set = true; - - if (isset($_COOKIE[$this->_params['session_name']])) { - if (isset($_COOKIE[$keyname . '_key'])) { - $key = $_COOKIE[$keyname . '_key']; - $set = false; - } else { - $key = $_COOKIE[$keyname . '_key'] = strval(new Horde_Support_Randomid()); - } - } else { - $key = session_id(); - } - - if ($set) { - $this->_setCookie($keyname, $key); - } - - return $key; - } - - /** - * Return a secret key, either from a cookie, or if the cookie - * isn't there, assume we are using a munged version of a known - * base value. - * - * @param string $keyname The name of the key to get. - * - * @return string The secret key. - */ - public function getKey($keyname = self::DEFAULT_KEY) - { - if (!isset($this->_keyCache[$keyname])) { - if (isset($_COOKIE[$keyname . '_key'])) { - $key = $_COOKIE[$keyname . '_key']; - } else { - $key = session_id(); - $this->_setCookie($keyname, $key); - } - - $this->_keyCache[$keyname] = $key; - } - - return $this->_keyCache[$keyname]; - } - - /** - * Clears a secret key entry from the current cookie. - * - * @param string $keyname The name of the key to clear. - * - * @return boolean True if key existed, false if not. - */ - public function clearKey($keyname = self::DEFAULT_KEY) - { - if (isset($_COOKIE[$this->_params['session_name']]) && - isset($_COOKIE[$keyname . '_key'])) { - $this->_setCookie($keyname, false); - return true; - } - - return false; - } - - /** - * Sets the cookie with the given keyname/key. - * - * @param string $keyname The name of the key to set. - * @param string $key The key to use for encryption. - */ - protected function _setCookie($keyname, $key) - { - @setcookie( - $keyname . '_key', - $key, - 0, - $this->_params['cookie_path'], - $this->_params['cookie_domain'], - $this->_params['cookie_ssl'], - true - ); - - if ($key === false) { - unset($_COOKIE[$keyname . '_key'], $this->_keyCache[$keyname]); - } else { - $_COOKIE[$keyname . '_key'] = $this->_keyCache[$keyname] = $key; - } - } - -} diff --git a/lib/horde/framework/Horde/Secret/Exception.php b/lib/horde/framework/Horde/Secret/Exception.php deleted file mode 100644 index bddfb4c2aaf..00000000000 --- a/lib/horde/framework/Horde/Secret/Exception.php +++ /dev/null @@ -1,21 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Secret - */ -class Horde_Secret_Exception extends Horde_Exception_Wrapped -{ - // Error codes. - const NO_BLOWFISH_LIB = 0; // 0 for BC - const KEY_NOT_STRING = 2; - const KEY_ZERO_LENGTH = 3; -} diff --git a/lib/horde/framework/Horde/Socket/Client.php b/lib/horde/framework/Horde/Socket/Client.php deleted file mode 100644 index 4d961c20c8f..00000000000 --- a/lib/horde/framework/Horde/Socket/Client.php +++ /dev/null @@ -1,337 +0,0 @@ - - * @author Jan Schneider - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Socket_Client - * - * @property-read boolean $connected Is there an active connection? - * @property-read boolean $secure Is the active connection secure? - */ -class Client -{ - /** - * Is there an active connection? - * - * @var boolean - */ - protected $_connected = false; - - /** - * Configuration parameters. - * - * @var array - */ - protected $_params; - - /** - * Is the connection secure? - * - * @var boolean - */ - protected $_secure = false; - - /** - * The actual socket. - * - * @var resource - */ - protected $_stream; - - /** - * Constructor. - * - * @param string $host Hostname of remote server (can contain - * protocol prefx). - * @param integer $port Port number of remote server. - * @param integer $timeout Connection timeout (in seconds). - * @param mixed $secure Security layer requested. One of: - * - false: (No encryption) [DEFAULT] - * - 'ssl': (Auto-detect SSL version) - * - 'sslv2': (Force SSL version 3) - * - 'sslv3': (Force SSL version 2) - * - 'tls': (TLS; started via protocol-level negotation over unencrypted - * channel) - * - 'tlsv1': (TLS version 1.x connection) - * - true: (TLS if available/necessary) - * @param array $context Any context parameters passed to - * stream_create_context(). - * @param array $params Additional options. - * - * @throws Horde\Socket\Client\Exception - */ - public function __construct( - $host, $port = null, $timeout = 30, $secure = false, - $context = array(), array $params = array() - ) - { - if ($secure && !extension_loaded('openssl')) { - if ($secure !== true) { - throw new \InvalidArgumentException('Secure connections require the PHP openssl extension.'); - } - $secure = false; - } - - $context = array_replace_recursive( - array( - 'ssl' => array( - 'verify_peer' => false, - 'verify_peer_name' => false - ) - ), - $context - ); - - $this->_params = $params; - - $this->_connect($host, $port, $timeout, $secure, $context); - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'connected': - return $this->_connected; - - case 'secure': - return $this->_secure; - } - } - - /** - * This object can not be cloned. - */ - public function __clone() - { - throw new \LogicException('Object cannot be cloned.'); - } - - /** - * This object can not be serialized. - */ - public function __sleep() - { - throw new \LogicException('Object can not be serialized.'); - } - - /** - * Start a TLS connection. - * - * @return boolean Whether TLS was successfully started. - */ - public function startTls() - { - if ($this->connected && !$this->secure) { - if (defined('STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT')) { - $mode = STREAM_CRYPTO_METHOD_TLS_CLIENT - | STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT - | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT - | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; - } else { - $mode = STREAM_CRYPTO_METHOD_TLS_CLIENT; - } - if (@stream_socket_enable_crypto($this->_stream, true, $mode) === true) { - $this->_secure = true; - return true; - } - } - - return false; - } - - /** - * Close the connection. - */ - public function close() - { - if ($this->connected) { - @fclose($this->_stream); - $this->_connected = $this->_secure = false; - $this->_stream = null; - } - } - - /** - * Returns information about the connection. - * - * Currently returns four entries in the result array: - * - timed_out (bool): The socket timed out waiting for data - * - blocked (bool): The socket was blocked - * - eof (bool): Indicates EOF event - * - unread_bytes (int): Number of bytes left in the socket buffer - * - * @throws Horde\Socket\Client\Exception - * @return array Information about existing socket resource. - */ - public function getStatus() - { - $this->_checkStream(); - return stream_get_meta_data($this->_stream); - } - - /** - * Returns a line of data. - * - * @param int $size Reading ends when $size - 1 bytes have been read, - * or a newline or an EOF (whichever comes first). - * - * @throws Horde\Socket\Client\Exception - * @return string $size bytes of data from the socket - */ - public function gets($size) - { - $this->_checkStream(); - $data = @fgets($this->_stream, $size); - if ($data === false) { - throw new Client\Exception('Error reading data from socket'); - } - return $data; - } - - /** - * Returns a specified amount of data. - * - * @param integer $size The number of bytes to read from the socket. - * - * @throws Horde\Socket\Client\Exception - * @return string $size bytes of data from the socket. - */ - public function read($size) - { - $this->_checkStream(); - $data = @fread($this->_stream, $size); - if ($data === false) { - throw new Client\Exception('Error reading data from socket'); - } - return $data; - } - - /** - * Writes data to the stream. - * - * @param string $data Data to write. - * - * @throws Horde\Socket\Client\Exception - */ - public function write($data) - { - $this->_checkStream(); - if (!@fwrite($this->_stream, $data)) { - $meta_data = $this->getStatus(); - if (!empty($meta_data['timed_out'])) { - throw new Client\Exception('Timed out writing data to socket'); - } - throw new Client\Exception('Error writing data to socket'); - } - } - - /* Internal methods. */ - - /** - * Connect to the remote server. - * - * @see __construct() - * - * @throws Horde\Socket\Client\Exception - */ - protected function _connect( - $host, $port, $timeout, $secure, $context, $retries = 0 - ) - { - $conn = ''; - if (!strpos($host, '://')) { - switch (strval($secure)) { - case 'ssl': - case 'sslv2': - case 'sslv3': - $conn = $secure . '://'; - $this->_secure = true; - break; - - case 'tlsv1': - $conn = 'tls://'; - $this->_secure = true; - break; - - case 'tls': - default: - $conn = 'tcp://'; - break; - } - } - $conn .= $host; - if ($port) { - $conn .= ':' . $port; - } - - $this->_stream = @stream_socket_client( - $conn, - $error_number, - $error_string, - $timeout, - STREAM_CLIENT_CONNECT, - stream_context_create($context) - ); - - if ($this->_stream === false) { - /* From stream_socket_client() page: a function return of false, - * with an error code of 0, indicates a "problem initializing the - * socket". These kind of issues are seen on the same server - * (and even the same user account) as sucessful connections, so - * these are likely transient issues. Retry up to 3 times in these - * instances. */ - if (!$error_number && ($retries < 3)) { - return $this->_connect($host, $port, $timeout, $secure, $context, ++$retries); - } - - $e = new Client\Exception( - 'Error connecting to server.' - ); - $e->details = sprintf("[%u] %s", $error_number, $error_string); - throw $e; - } - - stream_set_timeout($this->_stream, $timeout); - - if (function_exists('stream_set_read_buffer')) { - stream_set_read_buffer($this->_stream, 0); - } - stream_set_write_buffer($this->_stream, 0); - - $this->_connected = true; - } - - /** - * Throws an exception is the stream is not a resource. - * - * @throws Horde\Socket\Client\Exception - */ - protected function _checkStream() - { - if (!is_resource($this->_stream)) { - throw new Client\Exception('Not connected'); - } - } - -} diff --git a/lib/horde/framework/Horde/Socket/Client/Exception.php b/lib/horde/framework/Horde/Socket/Client/Exception.php deleted file mode 100644 index 3ab9c6f14e7..00000000000 --- a/lib/horde/framework/Horde/Socket/Client/Exception.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Socket_Client - */ -class Exception extends \Horde_Exception_Wrapped -{ -} diff --git a/lib/horde/framework/Horde/Stream.php b/lib/horde/framework/Horde/Stream.php deleted file mode 100644 index 0ca1578381c..00000000000 --- a/lib/horde/framework/Horde/Stream.php +++ /dev/null @@ -1,643 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream - * - * @property boolean $utf8_char Parse character as UTF-8 data instead of - * single byte (@since 1.4.0). - */ -class Horde_Stream implements Serializable -{ - /** - * Stream resource. - * - * @var resource - */ - public $stream; - - /** - * Configuration parameters. - * - * @var array - */ - protected $_params; - - /** - * Parse character as UTF-8 data instead of single byte. - * - * @var boolean - */ - protected $_utf8_char = false; - - /** - * Constructor. - * - * @param array $opts Configuration options. - */ - public function __construct(array $opts = array()) - { - $this->_params = $opts; - $this->_init(); - } - - /** - * Initialization method. - */ - protected function _init() - { - // Sane default: read-write, 0-length stream. - if (!$this->stream) { - $this->stream = @fopen('php://temp', 'r+'); - } - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'utf8_char': - return $this->_utf8_char; - } - } - - /** - */ - public function __set($name, $value) - { - switch ($name) { - case 'utf8_char': - $this->_utf8_char = (bool)$value; - break; - } - } - - /** - */ - public function __clone() - { - $data = strval($this); - $this->stream = null; - $this->_init(); - $this->add($data); - } - - /** - * String representation of object. - * - * @since 1.1.0 - * - * @return string The full stream converted to a string. - */ - public function __toString() - { - $this->rewind(); - return $this->substring(); - } - - /** - * Adds data to the stream. - * - * @param mixed $data Data to add to the stream. Can be a resource, - * Horde_Stream object, or a string(-ish) value. - * @param boolean $reset Reset stream pointer to initial position after - * adding? - */ - public function add($data, $reset = false) - { - if ($reset) { - $pos = $this->pos(); - } - - if (is_resource($data)) { - $dpos = ftell($data); - while (!feof($data)) { - $this->add(fread($data, 8192)); - } - fseek($data, $dpos); - } elseif ($data instanceof Horde_Stream) { - $dpos = $data->pos(); - while (!$data->eof()) { - $this->add($data->substring(0, 65536)); - } - $data->seek($dpos, false); - } else { - fwrite($this->stream, $data); - } - - if ($reset) { - $this->seek($pos, false); - } - } - - /** - * Returns the length of the data. Does not change the stream position. - * - * @param boolean $utf8 If true, determines the UTF-8 length of the - * stream (as of 1.4.0). If false, determines the - * byte length of the stream. - * - * @return integer Stream size. - * - * @throws Horde_Stream_Exception - */ - public function length($utf8 = false) - { - $pos = $this->pos(); - - if ($utf8 && $this->_utf8_char) { - $this->rewind(); - $len = 0; - while ($this->getChar() !== false) { - ++$len; - } - } elseif (!$this->end()) { - throw new Horde_Stream_Exception('ERROR'); - } else { - $len = $this->pos(); - } - - if (!$this->seek($pos, false)) { - throw new Horde_Stream_Exception('ERROR'); - } - - return $len; - } - - /** - * Get a string up to a certain character (or EOF). - * - * @param string $end The character to stop reading at. As of 1.4.0, - * $char can be a multi-character UTF-8 string. - * @param boolean $all If true, strips all repetitions of $end from - * the end. If false, stops at the first instance - * of $end. (@since 1.5.0) - * - * @return string The string up to $end (stream is positioned after the - * end character(s), all of which are stripped from the - * return data). - */ - public function getToChar($end, $all = true) - { - if (($len = strlen($end)) === 1) { - $out = ''; - do { - if (($tmp = stream_get_line($this->stream, 8192, $end)) === false) { - return $out; - } - - $out .= $tmp; - if ((strlen($tmp) < 8192) || ($this->peek(-1) == $end)) { - break; - } - } while (true); - } else { - $res = $this->search($end); - - if (is_null($res)) { - return $this->substring(); - } - - $out = substr($this->getString(null, $res + $len - 1), 0, $len * -1); - } - - /* Remove all further characters also. */ - if ($all) { - while ($this->peek($len) == $end) { - $this->seek($len); - } - } - - return $out; - } - - /** - * Return the current character(s) without moving the pointer. - * - * @param integer $length The peek length (since 1.4.0). - * - * @return string The current character. - */ - public function peek($length = 1) - { - $out = ''; - - for ($i = 0; $i < $length; ++$i) { - if (($c = $this->getChar()) === false) { - break; - } - $out .= $c; - } - - $this->seek(strlen($out) * -1); - - return $out; - } - - /** - * Search for character(s) and return its position. - * - * @param string $char The character to search for. As of 1.4.0, - * $char can be a multi-character UTF-8 string. - * @param boolean $reverse Do a reverse search? - * @param boolean $reset Reset the pointer to the original position? - * - * @return mixed The start position of the search string (integer), or - * null if character not found. - */ - public function search($char, $reverse = false, $reset = true) - { - $found_pos = null; - - if ($len = strlen($char)) { - $pos = $this->pos(); - $single_char = ($len === 1); - - do { - if ($reverse) { - for ($i = $pos - 1; $i >= 0; --$i) { - $this->seek($i, false); - $c = $this->peek(); - if ($c == ($single_char ? $char : substr($char, 0, strlen($c)))) { - $found_pos = $i; - break; - } - } - } else { - /* Optimization for the common use case of searching for - * a single character in byte data. Reduces calling - * getChar() a bunch of times. */ - $fgetc = ($single_char && !$this->_utf8_char); - - while (($c = ($fgetc ? fgetc($this->stream) : $this->getChar())) !== false) { - if ($c == ($single_char ? $char : substr($char, 0, strlen($c)))) { - $found_pos = $this->pos() - ($single_char ? 1 : strlen($c)); - break; - } - } - } - - if ($single_char || - is_null($found_pos) || - ($this->getString($found_pos, $found_pos + $len - 1) == $char)) { - break; - } - - $this->seek($found_pos + ($reverse ? 0 : 1), false); - $found_pos = null; - } while (true); - - $this->seek( - ($reset || is_null($found_pos)) ? $pos : $found_pos, - false - ); - } - - return $found_pos; - } - - /** - * Returns the stream (or a portion of it) as a string. Position values - * are the byte position in the stream. - * - * @param integer $start The starting position. If positive, start from - * this position. If negative, starts this length - * back from the current position. If null, starts - * from the current position. - * @param integer $end The ending position relative to the beginning of - * the stream (if positive). If negative, end this - * length back from the end of the stream. If null, - * reads to the end of the stream. - * - * @return string A string. - */ - public function getString($start = null, $end = null) - { - if (!is_null($start) && ($start >= 0)) { - $this->seek($start, false); - $start = 0; - } - - if (is_null($end)) { - $len = null; - } else { - $end = ($end >= 0) - ? $end - $this->pos() + 1 - : $this->length() - $this->pos() + $end; - $len = max($end, 0); - } - - return $this->substring($start, $len); - } - - /** - * Return part of the stream as a string. - * - * @since 1.4.0 - * - * @param integer $start Start, as an offset from the current postion. - * @param integer $length Length of string to return. If null, returns - * rest of the stream. If negative, this many - * characters will be omitted from the end of the - * stream. - * @param boolean $char If true, $start/$length is the length in - * characters. If false, $start/$length is the - * length in bytes. - * - * @return string The substring. - */ - public function substring($start = 0, $length = null, $char = false) - { - if ($start !== 0) { - $this->seek($start, true, $char); - } - - $out = ''; - $to_end = is_null($length); - - /* If length is greater than remaining stream, use more efficient - * algorithm below. Also, if doing a negative length, deal with that - * below also. */ - if ($char && - $this->_utf8_char && - !$to_end && - ($length >= 0) && - ($length < ($this->length() - $this->pos()))) { - while ($length-- && (($char = $this->getChar()) !== false)) { - $out .= $char; - } - return $out; - } - - if (!$to_end && ($length < 0)) { - $pos = $this->pos(); - $this->end(); - $this->seek($length, true, $char); - $length = $this->pos() - $pos; - $this->seek($pos, false); - if ($length < 0) { - return ''; - } - } - - while (!feof($this->stream) && ($to_end || $length)) { - $read = fread($this->stream, $to_end ? 16384 : $length); - $out .= $read; - if (!$to_end) { - $length -= strlen($read); - } - } - - return $out; - } - - /** - * Auto-determine the EOL string. - * - * @since 1.3.0 - * - * @return string The EOL string, or null if no EOL found. - */ - public function getEOL() - { - $pos = $this->pos(); - - $this->rewind(); - $pos2 = $this->search("\n", false, false); - if ($pos2) { - $this->seek(-1); - $eol = ($this->getChar() == "\r") - ? "\r\n" - : "\n"; - } else { - $eol = is_null($pos2) - ? null - : "\n"; - } - - $this->seek($pos, false); - - return $eol; - } - - /** - * Return a character from the string. - * - * @since 1.4.0 - * - * @return string Character (single byte, or UTF-8 character if - * $utf8_char is true). - */ - public function getChar() - { - $char = fgetc($this->stream); - if (!$this->_utf8_char) { - return $char; - } - - $c = ord($char); - if ($c < 0x80) { - return $char; - } - - if ($c < 0xe0) { - $n = 1; - } elseif ($c < 0xf0) { - $n = 2; - } elseif ($c < 0xf8) { - $n = 3; - } else { - throw new Horde_Stream_Exception('ERROR'); - } - - for ($i = 0; $i < $n; ++$i) { - if (($c = fgetc($this->stream)) === false) { - throw new Horde_Stream_Exception('ERROR'); - } - $char .= $c; - } - - return $char; - } - - /** - * Return the current stream pointer position. - * - * @since 1.4.0 - * - * @return mixed The current position (integer), or false. - */ - public function pos() - { - return ftell($this->stream); - } - - /** - * Rewind the internal stream to the beginning. - * - * @since 1.4.0 - * - * @return boolean True if successful. - */ - public function rewind() - { - return rewind($this->stream); - } - - /** - * Move internal pointer. - * - * @since 1.4.0 - * - * @param integer $offset The offset. - * @param boolean $curr If true, offset is from current position. If - * false, offset is from beginning of stream. - * @param boolean $char If true, $offset is the length in characters. - * If false, $offset is the length in bytes. - * - * @return boolean True if successful. - */ - public function seek($offset = 0, $curr = true, $char = false) - { - if (!$offset) { - return (bool)$curr ?: $this->rewind(); - } - - if ($offset < 0) { - if (!$curr) { - return true; - } elseif (abs($offset) > $this->pos()) { - return $this->rewind(); - } - } - - if ($char && $this->_utf8_char) { - if ($offset > 0) { - if (!$curr) { - $this->rewind(); - } - - do { - $this->getChar(); - } while (--$offset); - } else { - $pos = $this->pos(); - $offset = abs($offset); - - while ($pos-- && $offset) { - fseek($this->stream, -1, SEEK_CUR); - if ((ord($this->peek()) & 0xC0) != 0x80) { - --$offset; - } - } - } - - return true; - } - - return (fseek($this->stream, $offset, $curr ? SEEK_CUR : SEEK_SET) === 0); - } - - /** - * Move internal pointer to the end of the stream. - * - * @since 1.4.0 - * - * @param integer $offset Move this offset from the end. - * - * @return boolean True if successful. - */ - public function end($offset = 0) - { - return (fseek($this->stream, $offset, SEEK_END) === 0); - } - - /** - * Has the end of the stream been reached? - * - * @since 1.4.0 - * - * @return boolean True if the end of the stream has been reached. - */ - public function eof() - { - return feof($this->stream); - } - - /** - * Close the stream. - * - * @since 1.4.0 - */ - public function close() - { - if ($this->stream) { - fclose($this->stream); - } - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $data = @unserialize($data, true); - if ($data == null || !is_array($data)) { - throw new Exception('Cache version change.'); - } - $this->__unserialize($data); - } - - /** - * @return array - */ - public function __serialize() - { - $this->_params['_pos'] = $this->pos(); - - return array( - strval($this), - $this->_params - ); - } - - /** - * @param array $data - * @return void - */ - public function __unserialize($data) - { - $this->_init(); - $this->add($data[0]); - $this->seek($data[1]['_pos'], false); - unset($data[1]['_pos']); - $this->_params = $data[1]; - } - -} diff --git a/lib/horde/framework/Horde/Stream/Exception.php b/lib/horde/framework/Horde/Stream/Exception.php deleted file mode 100644 index 3c1a8855396..00000000000 --- a/lib/horde/framework/Horde/Stream/Exception.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream - */ -class Horde_Stream_Exception extends Horde_Exception_Wrapped -{ -} diff --git a/lib/horde/framework/Horde/Stream/Existing.php b/lib/horde/framework/Horde/Stream/Existing.php deleted file mode 100644 index bcab16a7f4a..00000000000 --- a/lib/horde/framework/Horde/Stream/Existing.php +++ /dev/null @@ -1,48 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream - */ -class Horde_Stream_Existing extends Horde_Stream -{ - /** - * Constructor. - * - * @param array $opts Additional configuration options: - * - stream: (resource) [REQUIRED] The stream resource. - * - * @throws InvalidArgumentException - */ - public function __construct(array $opts = array()) - { - if (!isset($opts['stream']) || !is_resource($opts['stream'])) { - throw new InvalidArgumentException('Need a stream resource.'); - } - - $this->stream = $opts['stream']; - unset($opts['stream']); - - parent::__construct($opts); - } - -} diff --git a/lib/horde/framework/Horde/Stream/Filter/Bin2hex.php b/lib/horde/framework/Horde/Stream/Filter/Bin2hex.php deleted file mode 100644 index 43503135e85..00000000000 --- a/lib/horde/framework/Horde/Stream/Filter/Bin2hex.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream_Filter - */ -class Horde_Stream_Filter_Bin2hex extends php_user_filter -{ - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function filter($in, $out, &$consumed, $closing) - { - while ($bucket = stream_bucket_make_writeable($in)) { - $bucket->data = bin2hex($bucket->data); - $consumed += $bucket->datalen; - stream_bucket_append($out, $bucket); - } - - return PSFS_PASS_ON; - } - -} diff --git a/lib/horde/framework/Horde/Stream/Filter/Crc32.php b/lib/horde/framework/Horde/Stream/Filter/Crc32.php deleted file mode 100644 index a6a1ba08dd3..00000000000 --- a/lib/horde/framework/Horde/Stream/Filter/Crc32.php +++ /dev/null @@ -1,125 +0,0 @@ - - * $params = new stdClass; - * stream_filter_register('horde_crc32', 'Horde_Stream_Filter_Crc32'); - * stream_filter_[app|pre]pend($stream, 'horde_crc32', - * [ STREAM_FILTER_[READ|WRITE|ALL] ], - * [ $params ]); - * while (fread($stream, 8192)) {} - * // CRC32 data in $params->crc32 - * - * - * Copyright 2011-2017 Horde LLC (http://www.horde.org/) - * - * See the enclosed file LICENSE for license information (LGPL). If you - * did not receive this file, see http://www.horde.org/licenses/lgpl21. - * - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream_Filter - */ -class Horde_Stream_Filter_Crc32 extends php_user_filter -{ - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function onCreate() - { - $this->params->crc32 = 0; - - return true; - } - - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function filter($in, $out, &$consumed, $closing) - { - while ($bucket = stream_bucket_make_writeable($in)) { - $consumed += $bucket->datalen; - $this->params->crc32 = $this->_crc32Combine($this->params->crc32, crc32($bucket->data), $bucket->datalen); - stream_bucket_append($out, $bucket); - } - - return PSFS_PASS_ON; - } - - /** - */ - protected function _crc32Combine($crc1, $crc2, $len2) - { - $odd = array(0xedb88320); - $row = 1; - - for ($n = 1; $n < 32; ++$n) { - $odd[$n] = $row; - $row <<= 1; - } - - $this->_gf2MatrixSquare($even, $odd); - $this->_gf2MatrixSquare($odd, $even); - - do { - /* Apply zeros operator for this bit of len2. */ - $this->_gf2MatrixSquare($even, $odd); - - if ($len2 & 1) { - $crc1 = $this->_gf2MatrixTimes($even, $crc1); - } - - $len2>>=1; - - /* If no more bits set, then done. */ - if ($len2 == 0) { - break; - } - - /* Another iteration of the loop with odd and even swapped. */ - $this->_gf2MatrixSquare($odd, $even); - if ($len2 & 1) { - $crc1 = $this->_gf2MatrixTimes($odd, $crc1); - } - - $len2>>= 1; - } while ($len2 != 0); - - $crc1 ^= $crc2; - - return $crc1; - } - - /** - */ - protected function _gf2MatrixSquare(&$square, &$mat) - { - for ($n = 0; $n < 32; ++$n) { - $square[$n] = $this->_gf2MatrixTimes($mat, $mat[$n]); - } - } - - /** - */ - protected function _gf2MatrixTimes($mat, $vec) - { - $i = $sum = 0; - - while ($vec) { - if ($vec & 1) { - $sum ^= $mat[$i]; - } - - $vec = ($vec >> 1) & 0x7FFFFFFF; - ++$i; - } - - return $sum; - } - -} diff --git a/lib/horde/framework/Horde/Stream/Filter/Eol.php b/lib/horde/framework/Horde/Stream/Filter/Eol.php deleted file mode 100644 index 7effb3f8ff6..00000000000 --- a/lib/horde/framework/Horde/Stream/Filter/Eol.php +++ /dev/null @@ -1,103 +0,0 @@ - ("\r\n") - * - * @author Michael Slusarz - * @category Horde - * @copyright 2009-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream_Filter - */ -class Horde_Stream_Filter_Eol extends php_user_filter -{ - /** - * Replacement data - * - * @var mixed - */ - protected $_replace; - - /** - * Search array. - * - * @var mixed - */ - protected $_search; - - /** - * First character of a multi-character EOL. - * - * @var string - */ - protected $_split = null; - - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function onCreate() - { - $eol = isset($this->params['eol']) - ? $this->params['eol'] - : "\r\n"; - - if (!strlen($eol)) { - $this->_search = array("\r", "\n"); - $this->_replace = ''; - } elseif (in_array($eol, array("\r", "\n"))) { - $this->_search = array("\r\n", ($eol == "\r") ? "\n" : "\r"); - $this->_replace = $eol; - } else { - $this->_search = array("\r\n", "\r", "\n"); - $this->_replace = array("\n", "\n", $eol); - if (strlen($eol) > 1) { - $this->_split = $eol[0]; - } - } - - return true; - } - - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function filter($in, $out, &$consumed, $closing) - { - while ($bucket = stream_bucket_make_writeable($in)) { - if (!is_null($this->_split) && - ($bucket->data[$bucket->datalen - 1] == $this->_split)) { - $bucket->data = substr($bucket->data, 0, -1); - } - - $bucket->data = str_replace($this->_search, $this->_replace, $bucket->data); - $consumed += $bucket->datalen; - stream_bucket_append($out, $bucket); - } - - return PSFS_PASS_ON; - } - -} diff --git a/lib/horde/framework/Horde/Stream/Filter/Htmlspecialchars.php b/lib/horde/framework/Horde/Stream/Filter/Htmlspecialchars.php deleted file mode 100644 index d3a52cb13f3..00000000000 --- a/lib/horde/framework/Horde/Stream/Filter/Htmlspecialchars.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream_Filter - */ -class Horde_Stream_Filter_Htmlspecialchars extends php_user_filter -{ - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function filter($in, $out, &$consumed, $closing) - { - while ($bucket = stream_bucket_make_writeable($in)) { - $bucket->data = htmlspecialchars($bucket->data); - $consumed += $bucket->datalen; - stream_bucket_append($out, $bucket); - } - - return PSFS_PASS_ON; - } -} diff --git a/lib/horde/framework/Horde/Stream/Filter/Null.php b/lib/horde/framework/Horde/Stream/Filter/Null.php deleted file mode 100644 index 25d18795f2b..00000000000 --- a/lib/horde/framework/Horde/Stream/Filter/Null.php +++ /dev/null @@ -1,69 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream_Filter - */ -class Horde_Stream_Filter_Null extends php_user_filter -{ - /** - * Search array. - * - * @var mixed - */ - protected $_search = "\0"; - - /** - * Replacement data - * - * @var mixed - */ - protected $_replace; - - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function onCreate() - { - $this->_replace = isset($this->params->replace) - ? $this->params->replace - : ''; - - return true; - } - - /** - * @see stream_filter_register() - */ - #[ReturnTypeWillChange] - public function filter($in, $out, &$consumed, $closing) - { - while ($bucket = stream_bucket_make_writeable($in)) { - $bucket->data = str_replace($this->_search, $this->_replace, $bucket->data); - $consumed += $bucket->datalen; - stream_bucket_append($out, $bucket); - } - - return PSFS_PASS_ON; - } - -} diff --git a/lib/horde/framework/Horde/Stream/String.php b/lib/horde/framework/Horde/Stream/String.php deleted file mode 100644 index b10946441e1..00000000000 --- a/lib/horde/framework/Horde/Stream/String.php +++ /dev/null @@ -1,49 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream - * @since 1.6.0 - */ -class Horde_Stream_String extends Horde_Stream -{ - /** - * Constructor. - * - * @param array $opts Additional configuration options: - *
-     *   - string: (string) [REQUIRED] The PHP string.
-     * 
- * - * @throws InvalidArgumentException - */ - public function __construct(array $opts = array()) - { - if (!isset($opts['string']) || !is_string($opts['string'])) { - throw new InvalidArgumentException('Need a PHP string.'); - } - - $this->stream = Horde_Stream_Wrapper_String::getStream($opts['string']); - unset($opts['string']); - - parent::__construct($opts); - } - -} diff --git a/lib/horde/framework/Horde/Stream/Temp.php b/lib/horde/framework/Horde/Stream/Temp.php deleted file mode 100644 index dee9fca57e0..00000000000 --- a/lib/horde/framework/Horde/Stream/Temp.php +++ /dev/null @@ -1,56 +0,0 @@ - - * @category Horde - * @copyright 2012-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream - */ -class Horde_Stream_Temp extends Horde_Stream -{ - /** - * Constructor. - * - * @param array $opts Additional configuration options: - *
-     *   - max_memory: (integer) The maximum amount of memory to allocate to
-     *                 the PHP temporary stream.
-     * 
- * - * @throws Horde_Stream_Exception - */ - public function __construct(array $opts = array()) - { - parent::__construct($opts); - } - - /** - * @throws Horde_Stream_Exception - */ - protected function _init() - { - $cmd = 'php://temp'; - if (isset($this->_params['max_memory'])) { - $cmd .= '/maxmemory:' . intval($this->_params['max_memory']); - } - - if (($this->stream = @fopen($cmd, 'r+')) === false) { - throw new Horde_Stream_Exception('Failed to open temporary memory stream.'); - } - } - -} diff --git a/lib/horde/framework/Horde/Stream/TempString.php b/lib/horde/framework/Horde/Stream/TempString.php deleted file mode 100644 index c80a8a08d26..00000000000 --- a/lib/horde/framework/Horde/Stream/TempString.php +++ /dev/null @@ -1,293 +0,0 @@ - - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Stream - * @since 1.6.0 - * - * @property-read boolean $use_stream If true, the object is using a PHP temp - * stream internally. - */ -class Horde_Stream_TempString extends Horde_Stream_Temp -{ - /** - * String stream object. - * - * @var Horde_Stream_String - */ - protected $_string; - - /** - */ - public function __construct(array $opts = array()) - { - parent::__construct($opts); - - $temp = ''; - $this->_string = new Horde_Stream_String(array( - 'string' => $temp - )); - } - - /** - */ - protected function _init() - { - if (!isset($this->_params['max_memory'])) { - $this->_params['max_memory'] = 2097152; - } - - if (!$this->_string) { - parent::_init(); - } - } - - /** - */ - public function __get($name) - { - switch ($name) { - case 'stream': - if ($this->_string) { - return $this->_string->stream; - } - break; - - case 'use_stream': - return !(bool)$this->_string; - } - - return parent::__get($name); - } - - /** - */ - public function __set($name, $value) - { - switch ($name) { - case 'utf8_char': - if ($this->_string) { - $this->_string->utf8_char = $value; - } - break; - } - - parent::__set($name, $value); - } - - /** - */ - public function __clone() - { - if ($this->_string) { - $this->_string = clone $this->_string; - } else { - parent::__clone(); - } - } - - /** - */ - public function __toString() - { - return $this->_string - ? strval($this->_string) - : parent::__toString(); - } - - /** - */ - public function add($data, $reset = false) - { - if ($this->_string && is_string($data)) { - if ((strlen($data) + $this->_string->length()) < $this->_params['max_memory']) { - $this->_string->add($data, $reset); - return; - } - - parent::_init(); - parent::add(strval($this->_string)); - $this->seek($this->_string->pos(), false); - unset($this->_string); - } - - parent::add($data, $reset); - } - - /** - */ - public function length($utf8 = false) - { - return $this->_string - ? $this->_string->length($utf8) - : parent::length($utf8); - } - - /** - */ - public function getToChar($end, $all = true) - { - return $this->_string - ? $this->_string->getToChar($end, $all) - : parent::getToChar($end, $all); - } - - - /** - */ - public function peek($length = 1) - { - return $this->_string - ? $this->_string->peek($length) - : parent::peek($length); - } - - /** - */ - public function search($char, $reverse = false, $reset = true) - { - return $this->_string - ? $this->_string->search($char, $reverse, $reset) - : parent::search($char, $reverse, $reset); - } - - /** - */ - public function getString($start = null, $end = null) - { - return $this->_string - ? $this->_string->getString($start, $end) - : parent::getString($start, $end); - } - - /** - */ - public function substring($start = 0, $length = null, $char = false) - { - return $this->_string - ? $this->_string->substring($start, $length, $char) - : parent::substring($start, $length, $char); - } - - /** - */ - public function getChar() - { - return $this->_string - ? $this->_string->getChar() - : parent::getChar(); - } - - /** - */ - public function pos() - { - return $this->_string - ? $this->_string->pos() - : parent::pos(); - } - - /** - */ - public function rewind() - { - return $this->_string - ? $this->_string->rewind() - : parent::rewind(); - } - - /** - */ - public function seek($offset = 0, $curr = true, $char = false) - { - return $this->_string - ? $this->_string->seek($offset, $curr, $char) - : parent::seek($offset, $curr, $char); - } - - /** - */ - public function end($offset = 0) - { - return $this->_string - ? $this->_string->end($offset) - : parent::end($offset); - } - - /** - */ - public function eof() - { - return $this->_string - ? $this->_string->eof() - : parent::eof(); - } - - /* Serializable methods. */ - - /** - */ - public function serialize() - { - return serialize($this->__serialize()); - } - - /** - */ - public function unserialize($data) - { - $this->__unserialize(unserialize($data)); - } - - /** - * @return array - */ - public function __serialize() - { - if ($this->_string) { - return array( - $this->_string, - $this->_params - ); - } else { - return parent::__serialize(); - } - } - - /** - * @param array $data - * @return void - */ - public function __unserialize($data) - { - if ($data[0] instanceof Horde_Stream_String) { - $this->_string = $data[0]; - $this->_params = $data[1]; - } else { - parent::__unserialize($data); - } - } - -} diff --git a/lib/horde/framework/Horde/Stream/Wrapper/Combine.php b/lib/horde/framework/Horde/Stream/Wrapper/Combine.php deleted file mode 100644 index d7a4a751af6..00000000000 --- a/lib/horde/framework/Horde/Stream/Wrapper/Combine.php +++ /dev/null @@ -1,317 +0,0 @@ - - * @category Horde - * @copyright 2009-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd BSD - * @package Stream_Wrapper - */ -class Horde_Stream_Wrapper_Combine -{ - /**/ - const WRAPPER_NAME = 'horde-stream-wrapper-combine'; - - /** - * Context. - * - * @var resource - */ - public $context; - - /** - * Array that holds the various streams. - * - * @var array - */ - protected $_data = array(); - - /** - * The combined length of the stream. - * - * @var integer - */ - protected $_length = 0; - - /** - * The current position in the string. - * - * @var integer - */ - protected $_position = 0; - - /** - * The current position in the data array. - * - * @var integer - */ - protected $_datapos = 0; - - /** - * Have we reached EOF? - * - * @var boolean - */ - protected $_ateof = false; - - /** - * Unique ID tracker for the streams. - * - * @var integer - */ - private static $_id = 0; - - /** - * Create a stream from multiple data sources. - * - * @since 2.1.0 - * - * @param array $data An array of strings and/or streams to combine into - * a single stream. - * - * @return resource A PHP stream. - */ - public static function getStream($data) - { - if (!self::$_id) { - stream_wrapper_register(self::WRAPPER_NAME, __CLASS__); - } - - return fopen( - self::WRAPPER_NAME . '://' . ++self::$_id, - 'wb', - false, - stream_context_create(array( - self::WRAPPER_NAME => array( - 'data' => $data - ) - )) - ); - } - /** - * @see streamWrapper::stream_open() - * - * @param string $path - * @param string $mode - * @param integer $options - * @param string &$opened_path - * - * @throws Exception - */ - public function stream_open($path, $mode, $options, &$opened_path) - { - $opts = stream_context_get_options($this->context); - - if (isset($opts[self::WRAPPER_NAME]['data'])) { - $data = $opts[self::WRAPPER_NAME]['data']; - } elseif (isset($opts['horde-combine']['data'])) { - // @deprecated - $data = $opts['horde-combine']['data']->getData(); - } else { - throw new Exception('Use ' . __CLASS__ . '::getStream() to initialize the stream.'); - } - - foreach ($data as $val) { - if (is_string($val)) { - $fp = fopen('php://temp', 'r+'); - fwrite($fp, $val); - } else { - $fp = $val; - } - - fseek($fp, 0, SEEK_END); - $length = ftell($fp); - rewind($fp); - - $this->_data[] = array( - 'fp' => $fp, - 'l' => $length, - 'p' => 0 - ); - - $this->_length += $length; - } - - return true; - } - - /** - * @see streamWrapper::stream_read() - * - * @param integer $count - * - * @return mixed - */ - public function stream_read($count) - { - if ($this->stream_eof()) { - return false; - } - - $out = ''; - $tmp = &$this->_data[$this->_datapos]; - - while ($count) { - if (!is_resource($tmp['fp'])) { - return false; - } - - $curr_read = min($count, $tmp['l'] - $tmp['p']); - if ($curr_read > 0) { - $out .= fread($tmp['fp'], $curr_read); - $count -= $curr_read; - $this->_position += $curr_read; - } - - if ($this->_position == $this->_length) { - if ($count) { - $this->_ateof = true; - break; - } else { - $tmp['p'] += $curr_read; - } - } elseif ($count) { - if (!isset($this->_data[++$this->_datapos])) { - return false; - } - $tmp = &$this->_data[$this->_datapos]; - rewind($tmp['fp']); - $tmp['p'] = 0; - } else { - $tmp['p'] += $curr_read; - } - } - - return $out; - } - - /** - * @see streamWrapper::stream_write() - * - * @param string $data - * - * @return integer - */ - public function stream_write($data) - { - $tmp = &$this->_data[$this->_datapos]; - - $oldlen = $tmp['l']; - $res = fwrite($tmp['fp'], $data); - if ($res === false) { - return false; - } - - $tmp['p'] = ftell($tmp['fp']); - if ($tmp['p'] > $oldlen) { - $tmp['l'] = $tmp['p']; - $this->_length += ($tmp['l'] - $oldlen); - } - - return $res; - } - - /** - * @see streamWrapper::stream_tell() - * - * @return integer - */ - public function stream_tell() - { - return $this->_position; - } - - /** - * @see streamWrapper::stream_eof() - * - * @return boolean - */ - public function stream_eof() - { - return $this->_ateof; - } - - /** - * @see streamWrapper::stream_stat() - * - * @return array - */ - public function stream_stat() - { - return array( - 'dev' => 0, - 'ino' => 0, - 'mode' => 0, - 'nlink' => 0, - 'uid' => 0, - 'gid' => 0, - 'rdev' => 0, - 'size' => $this->_length, - 'atime' => 0, - 'mtime' => 0, - 'ctime' => 0, - 'blksize' => 0, - 'blocks' => 0 - ); - } - - /** - * @see streamWrapper::stream_seek() - * - * @param integer $offset - * @param integer $whence SEEK_SET, SEEK_CUR, or SEEK_END - * - * @return boolean - */ - public function stream_seek($offset, $whence) - { - $oldpos = $this->_position; - $this->_ateof = false; - - switch ($whence) { - case SEEK_SET: - $offset = $offset; - break; - - case SEEK_CUR: - $offset = $this->_position + $offset; - break; - - case SEEK_END: - $offset = $this->_length + $offset; - break; - - default: - return false; - } - - $count = $this->_position = min($this->_length, $offset); - - foreach ($this->_data as $key => $val) { - if ($count < $val['l']) { - $this->_datapos = $key; - $val['p'] = $count; - fseek($val['fp'], $count, SEEK_SET); - break; - } - $count -= $val['l']; - } - - return ($oldpos != $this->_position); - } - -} diff --git a/lib/horde/framework/Horde/Stream/Wrapper/CombineStream.php b/lib/horde/framework/Horde/Stream/Wrapper/CombineStream.php deleted file mode 100644 index 97ab0993eec..00000000000 --- a/lib/horde/framework/Horde/Stream/Wrapper/CombineStream.php +++ /dev/null @@ -1,33 +0,0 @@ - - * @category Horde - * @deprecated Use Horde_Stream_Wrapper_Combine::getStream() - * @copyright 2009-2016 Horde LLC - * @license http://www.horde.org/licenses/bsd BSD - * @package Stream_Wrapper - */ -interface Horde_Stream_Wrapper_CombineStream -{ - /** - * Return a reference to the data. - * - * @return array - */ - public function getData(); -} - diff --git a/lib/horde/framework/Horde/Stream/Wrapper/String.php b/lib/horde/framework/Horde/Stream/Wrapper/String.php deleted file mode 100644 index e05deefd7d5..00000000000 --- a/lib/horde/framework/Horde/Stream/Wrapper/String.php +++ /dev/null @@ -1,211 +0,0 @@ - - * @author Michael Slusarz - * @category Horde - * @copyright 2007-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd BSD - * @package Stream_Wrapper - */ -class Horde_Stream_Wrapper_String -{ - /**/ - const WRAPPER_NAME = 'horde-stream-wrapper-string'; - - /** - * The current context. - * - * @var resource - */ - public $context; - - /** - * String position. - * - * @var integer - */ - protected $_pos; - - /** - * The string. - * - * @var string - */ - protected $_string; - - /** - * Unique ID tracker for the streams. - * - * @var integer - */ - private static $_id = 0; - - /** - * Create a stream from a PHP string. - * - * @since 2.1.0 - * - * @param string &$string A PHP string variable. - * - * @return resource A PHP stream pointing to the variable. - */ - public static function getStream(&$string) - { - if (!self::$_id) { - stream_wrapper_register(self::WRAPPER_NAME, __CLASS__); - } - - /* Needed to keep reference. */ - $ob = new stdClass; - $ob->string = &$string; - - return fopen( - self::WRAPPER_NAME . '://' . ++self::$_id, - 'wb', - false, - stream_context_create(array( - self::WRAPPER_NAME => array( - 'string' => $ob - ) - )) - ); - } - - /** - * @see streamWrapper::stream_open() - */ - public function stream_open($path, $mode, $options, &$opened_path) - { - $opts = stream_context_get_options($this->context); - - if (isset($opts[self::WRAPPER_NAME]['string'])) { - $this->_string =& $opts[self::WRAPPER_NAME]['string']->string; - } elseif (isset($opts['horde-string']['string'])) { - // @deprecated - $this->_string =& $opts['horde-string']['string']->getString(); - } else { - throw new Exception('Use ' . __CLASS__ . '::getStream() to initialize the stream.'); - } - - if (is_null($this->_string)) { - return false; - } - - $this->_pos = 0; - - return true; - } - - /** - * @see streamWrapper::stream_close() - */ - public function stream_close() - { - $this->_string = ''; - $this->_pos = 0; - } - - /** - * @see streamWrapper::stream_read() - */ - public function stream_read($count) - { - $curr = $this->_pos; - $this->_pos += $count; - return substr($this->_string, $curr, $count); - } - - /** - * @see streamWrapper::stream_write() - */ - public function stream_write($data) - { - $len = strlen($data); - - $this->_string = substr_replace($this->_string, $data, $this->_pos, $len); - $this->_pos += $len; - - return $len; - } - - /** - * @see streamWrapper::stream_tell() - */ - public function stream_tell() - { - return $this->_pos; - } - - /** - * @see streamWrapper::stream_eof() - */ - public function stream_eof() - { - return ($this->_pos > strlen($this->_string)); - } - - /** - * @see streamWrapper::stream_stat() - */ - public function stream_stat() - { - return array( - 'dev' => 0, - 'ino' => 0, - 'mode' => 0, - 'nlink' => 0, - 'uid' => 0, - 'gid' => 0, - 'rdev' => 0, - 'size' => strlen($this->_string), - 'atime' => 0, - 'mtime' => 0, - 'ctime' => 0, - 'blksize' => 0, - 'blocks' => 0 - ); - } - - /** - * @see streamWrapper::stream_seek() - */ - public function stream_seek($offset, $whence) - { - switch ($whence) { - case SEEK_SET: - $pos = $offset; - break; - - case SEEK_CUR: - $pos = $this->_pos + $offset; - break; - - case SEEK_END: - $pos = strlen($this->_string) + $offset; - break; - } - - if (($pos < 0) || ($pos > strlen($this->_string))) { - return false; - } - - $this->_pos = $pos; - - return true; - } - -} diff --git a/lib/horde/framework/Horde/Stream/Wrapper/StringStream.php b/lib/horde/framework/Horde/Stream/Wrapper/StringStream.php deleted file mode 100644 index bb38341c8a5..00000000000 --- a/lib/horde/framework/Horde/Stream/Wrapper/StringStream.php +++ /dev/null @@ -1,32 +0,0 @@ - - * @category Horde - * @copyright 2007-2016 Horde LLC - * @deprecated Use Horde_Stream_Wrapper_String::getStream() - * @license http://www.horde.org/licenses/bsd BSD - * @package Stream_Wrapper - */ -interface Horde_Stream_Wrapper_StringStream -{ - /** - * Return a reference to the wrapped string. - * - * @return string - */ - public function &getString(); -} diff --git a/lib/horde/framework/Horde/String.php b/lib/horde/framework/Horde/String.php deleted file mode 100644 index ff7479ba9b6..00000000000 --- a/lib/horde/framework/Horde/String.php +++ /dev/null @@ -1,932 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Util - */ -class Horde_String -{ - /** - * lower() cache. - * - * @var array - */ - protected static $_lowers = array(); - - /** - * upper() cache. - * - * @var array - */ - protected static $_uppers = array(); - - /** - * Converts a string from one charset to another. - * - * Uses the iconv or the mbstring extensions. - * The original string is returned if conversion failed or none - * of the extensions were available. - * - * @param mixed $input The data to be converted. If $input is an an - * array, the array's values get converted - * recursively. - * @param string $from The string's current charset. - * @param string $to The charset to convert the string to. - * @param boolean $force Force conversion? - * - * @return mixed The converted input data. - */ - public static function convertCharset($input, $from, $to, $force = false) - { - /* Don't bother converting numbers. */ - if (is_numeric($input)) { - return $input; - } - - /* If the from and to character sets are identical, return now. */ - if (!$force && $from == $to) { - return $input; - } - $from = self::lower($from); - $to = self::lower($to); - if (!$force && $from == $to) { - return $input; - } - - if (is_array($input)) { - $tmp = array(); - foreach ($input as $key => $val) { - $tmp[self::_convertCharset($key, $from, $to)] = self::convertCharset($val, $from, $to, $force); - } - return $tmp; - } - - if (is_object($input)) { - // PEAR_Error/Exception objects are almost guaranteed to contain - // recursion, which will cause a segfault in PHP. We should never - // reach this line, but add a check. - if (($input instanceof Exception) || - ($input instanceof PEAR_Error)) { - return ''; - } - - $input = clone $input; - $vars = get_object_vars($input); - foreach ($vars as $key => $val) { - $input->$key = self::convertCharset($val, $from, $to, $force); - } - return $input; - } - - if (!is_string($input)) { - return $input; - } - - return self::_convertCharset($input, $from, $to); - } - - /** - * Internal function used to do charset conversion. - * - * @param string $input See self::convertCharset(). - * @param string $from See self::convertCharset(). - * @param string $to See self::convertCharset(). - * - * @return string The converted string. - */ - protected static function _convertCharset($input, $from, $to) - { - /* Use utf8_[en|de]code() if possible and if the string isn't too - * large (less than 16 MB = 16 * 1024 * 1024 = 16777216 bytes) - these - * functions use more memory. */ - if (Horde_Util::extensionExists('xml') && - ((strlen($input) < 16777216) || - !Horde_Util::extensionExists('iconv') || - !Horde_Util::extensionExists('mbstring'))) { - if (($to == 'utf-8') && - function_exists('utf8_encode') && - in_array($from, array('iso-8859-1', 'us-ascii', 'utf-8'))) { - return @utf8_encode($input); - } - - if (($from == 'utf-8') && - function_exists('utf8_decode') && - in_array($to, array('iso-8859-1', 'us-ascii', 'utf-8'))) { - return @utf8_decode($input); - } - } - - /* Try UTF7-IMAP conversions. */ - if (($from == 'utf7-imap') || ($to == 'utf7-imap')) { - try { - if ($from == 'utf7-imap') { - return self::convertCharset(Horde_Imap_Client_Utf7imap::Utf7ImapToUtf8($input), 'UTF-8', $to); - } else { - if ($from == 'utf-8') { - $conv = $input; - } else { - $conv = self::convertCharset($input, $from, 'UTF-8'); - } - return Horde_Imap_Client_Utf7imap::Utf8ToUtf7Imap($conv); - } - } catch (Horde_Imap_Client_Exception $e) { - return $input; - } - } - - /* Try iconv with transliteration. */ - if (Horde_Util::extensionExists('iconv')) { - unset($php_errormsg); - ini_set('track_errors', 1); - $out = @iconv($from, $to . '//TRANSLIT', $input); - $errmsg = isset($php_errormsg); - ini_restore('track_errors'); - if (!$errmsg && $out !== false) { - return $out; - } - } - - /* Try mbstring. */ - if (Horde_Util::extensionExists('mbstring')) { - try { - $out = @mb_convert_encoding($input, $to, self::_mbstringCharset($from)); - if (!empty($out)) { - return $out; - } - } catch (ValueError $e) { - // catch error thrown under PHP 8.0, if mbstring does not support the encoding - } - } - - return $input; - } - - /** - * Makes a string lowercase. - * - * @param string $string The string to be converted. - * @param boolean $locale If true the string will be converted based on - * a given charset, locale independent else. - * @param string $charset If $locale is true, the charset to use when - * converting. - * - * @return string The string with lowercase characters. - */ - public static function lower($string, $locale = false, $charset = null) - { - if ($locale) { - if (Horde_Util::extensionExists('mbstring')) { - if (is_null($charset)) { - throw new InvalidArgumentException('$charset argument must not be null'); - } - $ret = @mb_strtolower($string, self::_mbstringCharset($charset)); - if (!empty($ret)) { - return $ret; - } - } - return strtolower($string); - } - - if (!isset(self::$_lowers[$string])) { - $language = setlocale(LC_CTYPE, 0); - setlocale(LC_CTYPE, 'C'); - if ($string === null) { - self::$_lowers[$string] = ''; - } else { - self::$_lowers[$string] = strtolower($string); - } - setlocale(LC_CTYPE, $language); - } - - return self::$_lowers[$string]; - } - - /** - * Makes a string uppercase. - * - * @param string $string The string to be converted. - * @param boolean $locale If true the string will be converted based on a - * given charset, locale independent else. - * @param string $charset If $locale is true, the charset to use when - * converting. If not provided the current charset. - * - * @return string The string with uppercase characters. - */ - public static function upper($string, $locale = false, $charset = null) - { - if ($locale) { - if (Horde_Util::extensionExists('mbstring')) { - if (is_null($charset)) { - throw new InvalidArgumentException('$charset argument must not be null'); - } - $ret = @mb_strtoupper($string, self::_mbstringCharset($charset)); - if (!empty($ret)) { - return $ret; - } - } - return strtoupper($string); - } - - if (!isset(self::$_uppers[$string])) { - $language = setlocale(LC_CTYPE, 0); - setlocale(LC_CTYPE, 'C'); - self::$_uppers[$string] = strtoupper($string); - setlocale(LC_CTYPE, $language); - } - - return self::$_uppers[$string]; - } - - /** - * Returns a string with the first letter capitalized if it is - * alphabetic. - * - * @param string $string The string to be capitalized. - * @param boolean $locale If true the string will be converted based on a - * given charset, locale independent else. - * @param string $charset The charset to use, defaults to current charset. - * - * @return string The capitalized string. - */ - public static function ucfirst($string, $locale = false, $charset = null) - { - if ($locale) { - if (is_null($charset)) { - throw new InvalidArgumentException('$charset argument must not be null'); - } - $first = self::substr($string, 0, 1, $charset); - if (self::isAlpha($first, $charset)) { - $string = self::upper($first, true, $charset) . self::substr($string, 1, null, $charset); - } - } else { - $string = self::upper(substr($string, 0, 1), false) . substr($string, 1); - } - - return $string; - } - - /** - * Returns a string with the first letter of each word capitalized if it is - * alphabetic. - * - * Sentences are splitted into words at whitestrings. - * - * @param string $string The string to be capitalized. - * @param boolean $locale If true the string will be converted based on a - * given charset, locale independent else. - * @param string $charset The charset to use, defaults to current charset. - * - * @return string The capitalized string. - */ - public static function ucwords($string, $locale = false, $charset = null) - { - $words = preg_split('/(\s+)/', $string, -1, PREG_SPLIT_DELIM_CAPTURE); - for ($i = 0, $c = count($words); $i < $c; $i += 2) { - $words[$i] = self::ucfirst($words[$i], $locale, $charset); - } - return implode('', $words); - } - - /** - * Returns part of a string. - * - * @param string $string The string to be converted. - * @param integer $start The part's start position, zero based. - * @param integer $length The part's length. - * @param string $charset The charset to use when calculating the part's - * position and length, defaults to current - * charset. - * - * @return string The string's part. - */ - public static function substr($string, $start, $length = null, - $charset = 'UTF-8') - { - if (is_null($length)) { - $length = self::length($string, $charset) - $start; - } - - if ($length === 0) { - return ''; - } - - $error = false; - - /* Try mbstring. */ - if (Horde_Util::extensionExists('mbstring')) { - $ret = @mb_substr($string, $start, $length, self::_mbstringCharset($charset)); - - /* mb_substr() returns empty string on failure. */ - if (strlen($ret)) { - return $ret; - } - $error = true; - } - - /* Try iconv. */ - if (Horde_Util::extensionExists('iconv')) { - $ret = @iconv_substr($string, $start, $length, $charset); - - /* iconv_substr() returns false on failure. */ - if ($ret !== false) { - return $ret; - } - $error = true; - } - - /* Try intl. */ - if (Horde_Util::extensionExists('intl')) { - $ret = self::convertCharset( - @grapheme_substr( - self::convertCharset($string, $charset, 'UTF-8'), - $start, - $length - ), - 'UTF-8', - $charset - ); - - /* grapheme_substr() returns false on failure. */ - if ($ret !== false) { - return $ret; - } - $error = true; - } - - return $error - ? '' - : substr($string, $start, $length); - } - - /** - * Returns the character (not byte) length of a string. - * - * @param string $string The string to return the length of. - * @param string $charset The charset to use when calculating the string's - * length. - * - * @return integer The string's length. - */ - public static function length($string, $charset = 'UTF-8') - { - $charset = self::lower($charset); - - if ($charset == 'utf-8' || $charset == 'utf8') { - if (Horde_Util::extensionExists('mbstring')) { - return strlen(mb_convert_encoding($string, 'ISO-8859-1', 'UTF-8')); - - } else if (function_exists('utf8_decode')) { - return strlen(@utf8_decode($string)); - } - } - - if (Horde_Util::extensionExists('mbstring')) { - $ret = @mb_strlen($string, self::_mbstringCharset($charset)); - if (!empty($ret)) { - return $ret; - } - } - if (Horde_Util::extensionExists('intl')) { - return grapheme_strlen( - self::convertCharset($string, $charset, 'UTF-8') - ); - } - - return strlen($string); - } - - /** - * Returns the numeric position of the first occurrence of $needle - * in the $haystack string. - * - * @param string $haystack The string to search through. - * @param string $needle The string to search for. - * @param integer $offset Character in $haystack to start searching at. - * @param string $charset Charset of $needle. - * - * @return integer The position of first occurrence. - */ - public static function pos( - $haystack, $needle, $offset = 0, $charset = 'UTF-8' - ) - { - return self::_pos($haystack, $needle, $offset, $charset, 'strpos'); - } - - /** - * Returns the numeric position of the first case-insensitive occurrence - * of $needle in the $haystack string. - * - * @since 2.5.0 - * - * @param string $haystack The string to search through. - * @param string $needle The string to search for. - * @param integer $offset Character in $haystack to start searching at. - * @param string $charset Charset of $needle. - * - * @return integer The position of first case-insensitive occurrence. - */ - public static function ipos( - $haystack, $needle, $offset = 0, $charset = 'UTF-8' - ) - { - return self::_pos($haystack, $needle, $offset, $charset, 'stripos'); - } - - /** - * Returns the numeric position of the last occurrence of $needle - * in the $haystack string. - * - * @param string $haystack The string to search through. - * @param string $needle The string to search for. - * @param integer $offset Character in $haystack to start searching at. - * @param string $charset Charset of $needle. - * - * @return integer The position of last occurrence. - */ - public static function rpos( - $haystack, $needle, $offset = 0, $charset = 'UTF-8' - ) - { - return self::_pos($haystack, $needle, $offset, $charset, 'strrpos'); - } - - /** - * Returns the numeric position of the last case-insensitive occurrence of - * $needle in the $haystack string. - * - * @since 2.5.0 - * - * @param string $haystack The string to search through. - * @param string $needle The string to search for. - * @param integer $offset Character in $haystack to start searching at. - * @param string $charset Charset of $needle. - * - * @return integer The position of last case-insensitive occurrence. - */ - public static function ripos( - $haystack, $needle, $offset = 0, $charset = 'UTF-8' - ) - { - return self::_pos($haystack, $needle, $offset, $charset, 'strripos'); - } - - /** - * Perform string position searches. - * - * @param string $haystack The string to search through. - * @param string $needle The string to search for. - * @param integer $offset Character in $haystack to start searching at. - * @param string $charset Charset of $needle. - * @param string $func Function to use. - * - * @return integer The position of occurrence. - * - */ - protected static function _pos( - $haystack, $needle, $offset, $charset, $func - ) - { - if (Horde_Util::extensionExists('mbstring')) { - unset($php_errormsg); - $track_errors = ini_set('track_errors', 1); - $ret = @call_user_func('mb_' . $func, $haystack, $needle, $offset, self::_mbstringCharset($charset)); - ini_set('track_errors', $track_errors); - if (!isset($php_errormsg)) { - return $ret; - } - } - - if (Horde_Util::extensionExists('intl')) { - unset($php_errormsg); - $track_errors = ini_set('track_errors', 1); - $ret = self::convertCharset( - @call_user_func( - 'grapheme_' . $func, - self::convertCharset($haystack, $charset, 'UTF-8'), - self::convertCharset($needle, $charset, 'UTF-8'), - $offset - ), - 'UTF-8', - $charset - ); - ini_set('track_errors', $track_errors); - if (!isset($php_errormsg)) { - return $ret; - } - } - - return $func($haystack, $needle, $offset); - } - - /** - * Returns a string padded to a certain length with another string. - * This method behaves exactly like str_pad() but is multibyte safe. - * - * @param string $input The string to be padded. - * @param integer $length The length of the resulting string. - * @param string $pad The string to pad the input string with. Must - * be in the same charset like the input string. - * @param const $type The padding type. One of STR_PAD_LEFT, - * STR_PAD_RIGHT, or STR_PAD_BOTH. - * @param string $charset The charset of the input and the padding - * strings. - * - * @return string The padded string. - */ - public static function pad($input, $length, $pad = ' ', - $type = STR_PAD_RIGHT, $charset = 'UTF-8') - { - $mb_length = self::length($input, $charset); - $sb_length = strlen($input); - $pad_length = self::length($pad, $charset); - - /* Return if we already have the length. */ - if ($mb_length >= $length) { - return $input; - } - - /* Shortcut for single byte strings. */ - if ($mb_length == $sb_length && $pad_length == strlen($pad)) { - return str_pad($input, $length, $pad, $type); - } - - switch ($type) { - case STR_PAD_LEFT: - $left = $length - $mb_length; - $output = self::substr(str_repeat($pad, ceil($left / $pad_length)), 0, $left, $charset) . $input; - break; - - case STR_PAD_BOTH: - $left = floor(($length - $mb_length) / 2); - $right = ceil(($length - $mb_length) / 2); - $output = self::substr(str_repeat($pad, ceil($left / $pad_length)), 0, $left, $charset) . - $input . - self::substr(str_repeat($pad, ceil($right / $pad_length)), 0, $right, $charset); - break; - - case STR_PAD_RIGHT: - $right = $length - $mb_length; - $output = $input . self::substr(str_repeat($pad, ceil($right / $pad_length)), 0, $right, $charset); - break; - } - - return $output; - } - - /** - * Wraps the text of a message. - * - * @param string $string String containing the text to wrap. - * @param integer $width Wrap the string at this number of - * characters. - * @param string $break Character(s) to use when breaking lines. - * @param boolean $cut Whether to cut inside words if a line - * can't be wrapped. - * @param boolean $line_folding Whether to apply line folding rules per - * RFC 822 or similar. The correct break - * characters including leading whitespace - * have to be specified too. - * - * @return string String containing the wrapped text. - */ - public static function wordwrap($string, $width = 75, $break = "\n", - $cut = false, $line_folding = false) - { - $breakRegex = '(?:' . preg_quote($break) . ')'; - $rpos = self::rpos($break, "\n"); - if ($rpos === false) { - $rpos = 0; - } else { - $rpos++; - } - $wrapped = ''; - $hasWrapped = false; - - while (self::length($string, 'UTF-8') > $width) { - $line = self::substr($string, 0, $width + ($hasWrapped ? $rpos : 0), 'UTF-8'); - $string = self::substr($string, self::length($line, 'UTF-8'), null, 'UTF-8'); - - // Make sure we didn't cut a word, unless we want hard breaks - // anyway. - if (!$cut && preg_match('/^(.+?)((\s|\r?\n).*)/us', $string, $match)) { - $line .= $match[1]; - $string = $match[2]; - } - - // Wrap at existing line breaks. - $regex = '/^(' . ($hasWrapped ? $breakRegex : '') . '.*?)(\r?\n)(.*)$/us'; - if (preg_match($regex, $line, $match)) { - $wrapped .= $match[1] . $match[2]; - $string = $match[3] . $string; - $hasWrapped = false; - continue; - } - - // Wrap at the last colon or semicolon followed by a whitespace if - // doing line folding. - if ($line_folding && - preg_match('/^(.*?)(;|:)(\s+.*)$/us', $line, $match)) { - $wrapped .= $match[1] . $match[2]; - $string = $break . $match[3] . $string; - $hasWrapped = true; - continue; - } - - // Wrap at the last whitespace of $line. - $sub = $line_folding - ? '(' . ($hasWrapped ? $breakRegex : '') . '.+[^\s])' - : '(' . ($hasWrapped ? $breakRegex : '') . '.*)'; - - if (preg_match('/^' . $sub . '(\s+)(.*)$/u', $line, $match)) { - $wrapped .= $match[1]; - $string = $break . ($line_folding ? $match[2] : '') - . $match[3] . $string; - $hasWrapped = true; - continue; - } - - // Hard wrap if necessary. - if ($cut) { - $wrapped .= $line; - $string = $break . $string; - $hasWrapped = true; - continue; - } - - $wrapped .= $line; - $hasWrapped = false; - } - - return $wrapped . $string; - } - - /** - * Wraps the text of a message. - * - * @param string $text String containing the text to wrap. - * @param integer $length Wrap $text at this number of characters. - * @param string $break_char Character(s) to use when breaking lines. - * @param boolean $quote Ignore lines that are wrapped with the '>' - * character (RFC 2646)? If true, we don't - * remove any padding whitespace at the end of - * the string. - * - * @return string String containing the wrapped text. - */ - public static function wrap($text, $length = 80, $break_char = "\n", - $quote = false) - { - $paragraphs = array(); - - foreach (preg_split('/\r?\n/', $text) as $input) { - if ($quote && (strpos($input, '>') === 0)) { - $line = $input; - } else { - /* We need to handle the Usenet-style signature line - * separately; since the space after the two dashes is - * REQUIRED, we don't want to trim the line. */ - if ($input != '-- ') { - $input = rtrim($input); - } - $line = self::wordwrap($input, $length, $break_char); - } - - $paragraphs[] = $line; - } - - return implode($break_char, $paragraphs); - } - - /** - * Return a truncated string, suitable for notifications. - * - * @param string $text The original string. - * @param integer $length The maximum length. - * - * @return string The truncated string, if longer than $length. - */ - public static function truncate($text, $length = 100) - { - return (self::length($text) > $length) - ? rtrim(self::substr($text, 0, $length - 3)) . '...' - : $text; - } - - /** - * Return an abbreviated string, with characters in the middle of the - * excessively long string replaced by '...'. - * - * @param string $text The original string. - * @param integer $length The length at which to abbreviate. - * - * @return string The abbreviated string, if longer than $length. - */ - public static function abbreviate($text, $length = 20) - { - return (self::length($text) > $length) - ? rtrim(self::substr($text, 0, round(($length - 3) / 2))) . '...' . ltrim(self::substr($text, (($length - 3) / 2) * -1)) - : $text; - } - - /** - * Returns the common leading part of two strings. - * - * @param string $str1 A string. - * @param string $str2 Another string. - * - * @return string The start of $str1 and $str2 that is identical in both. - */ - public static function common($str1, $str2) - { - for ($result = '', $i = 0; - isset($str1[$i]) && isset($str2[$i]) && $str1[$i] == $str2[$i]; - $i++) { - $result .= $str1[$i]; - } - return $result; - } - - /** - * Returns true if the every character in the parameter is an alphabetic - * character. - * - * @param string $string The string to test. - * @param string $charset The charset to use when testing the string. - * - * @return boolean True if the parameter was alphabetic only. - */ - public static function isAlpha($string, $charset) - { - if (!Horde_Util::extensionExists('mbstring')) { - return ctype_alpha($string); - } - - $charset = self::_mbstringCharset($charset); - $old_charset = mb_regex_encoding(); - - if ($charset != $old_charset) { - @mb_regex_encoding($charset); - } - $alpha = !@mb_ereg_match('[^[:alpha:]]', $string); - if ($charset != $old_charset) { - @mb_regex_encoding($old_charset); - } - - return $alpha; - } - - /** - * Returns true if ever character in the parameter is a lowercase letter in - * the current locale. - * - * @param string $string The string to test. - * @param string $charset The charset to use when testing the string. - * - * @return boolean True if the parameter was lowercase. - */ - public static function isLower($string, $charset) - { - return ((self::lower($string, true, $charset) === $string) && - self::isAlpha($string, $charset)); - } - - /** - * Returns true if every character in the parameter is an uppercase letter - * in the current locale. - * - * @param string $string The string to test. - * @param string $charset The charset to use when testing the string. - * - * @return boolean True if the parameter was uppercase. - */ - public static function isUpper($string, $charset) - { - return ((self::upper($string, true, $charset) === $string) && - self::isAlpha($string, $charset)); - } - - /** - * Performs a multibyte safe regex match search on the text provided. - * - * @param string $text The text to search. - * @param array $regex The regular expressions to use, without perl - * regex delimiters (e.g. '/' or '|'). - * @param string $charset The character set of the text. - * - * @return array The matches array from the first regex that matches. - */ - public static function regexMatch($text, $regex, $charset = null) - { - if (!empty($charset)) { - $regex = self::convertCharset($regex, $charset, 'utf-8'); - $text = self::convertCharset($text, $charset, 'utf-8'); - } - - $matches = array(); - foreach ($regex as $val) { - if (preg_match('/' . $val . '/u', $text, $matches)) { - break; - } - } - - if (!empty($charset)) { - $matches = self::convertCharset($matches, 'utf-8', $charset); - } - - return $matches; - } - - /** - * Check to see if a string is valid UTF-8. - * - * @param string $text The text to check. - * - * @return boolean True if valid UTF-8. - */ - public static function validUtf8($text) - { - $text = strval($text); - - // First check for illegal surrogate pair sequences. See RFC 3629. - if (preg_match('/\xE0[\x80-\x9F][\x80-\xBF]|\xED[\xA0-\xBF][\x80-\xBF]/S', $text)) { - return false; - } - - for ($i = 0, $len = strlen($text); $i < $len; ++$i) { - $c = ord($text[$i]); - if ($c > 128) { - if ($c > 247) { - // STD 63 (RFC 3629) eliminates 5 & 6-byte characters. - return false; - } elseif ($c > 239) { - $j = 3; - } elseif ($c > 223) { - $j = 2; - } elseif ($c > 191) { - $j = 1; - } else { - return false; - } - - if (($i + $j) > $len) { - return false; - } - - do { - $c = ord($text[++$i]); - if (($c < 128) || ($c > 191)) { - return false; - } - } while (--$j); - } - } - - return true; - } - - /** - * Workaround charsets that don't work with mbstring functions. - * - * @param string $charset The original charset. - * - * @return string The charset to use with mbstring functions. - */ - protected static function _mbstringCharset($charset) - { - /* mbstring functions do not handle the 'ks_c_5601-1987' & - * 'ks_c_5601-1989' charsets. However, these charsets are used, for - * example, by various versions of Outlook to send Korean characters. - * Use UHC (CP949) encoding instead. See, e.g., - * http://lists.w3.org/Archives/Public/ietf-charsets/2001AprJun/0030.html */ - return in_array(self::lower($charset), array('ks_c_5601-1987', 'ks_c_5601-1989')) - ? 'UHC' - : $charset; - } - - /** - * Strip UTF-8 byte order mark (BOM) from string data. - * - * @param string $str Input string (UTF-8). - * - * @return string Stripped string (UTF-8). - */ - public static function trimUtf8Bom($str) - { - return (substr($str, 0, 3) == pack('CCC', 239, 187, 191)) - ? substr($str, 3) - : $str; - } - -} diff --git a/lib/horde/framework/Horde/String/Transliterate.php b/lib/horde/framework/Horde/String/Transliterate.php deleted file mode 100644 index f1220a9f9c6..00000000000 --- a/lib/horde/framework/Horde/String/Transliterate.php +++ /dev/null @@ -1,195 +0,0 @@ - - * @author Jan Schneider - * @category Horde - * @copyright 2014-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Util - * @since 2.4.0 - */ -class Horde_String_Transliterate -{ - /** - * Transliterate mapping cache. - * - * @var array - */ - protected static $_map; - - /** - * Transliterator instance. - * - * @var Transliterator - */ - protected static $_transliterator; - - /** - * Transliterates an UTF-8 string to ASCII, replacing non-English - * characters to their English equivalents. - * - * Note: there is no guarantee that the output string will be ASCII-only, - * since any non-ASCII character not in the transliteration list will - * be ignored. - * - * @param string $str Input string (UTF-8). - * - * @return string Transliterated string (UTF-8). - */ - public static function toAscii($str) - { - $methods = array( - '_intlToAscii', - '_iconvToAscii', - '_fallbackToAscii' - ); - - foreach ($methods as $val) { - if (($out = call_user_func(array(__CLASS__, $val), $str)) !== false) { - return $out; - } - } - - return $str; - } - - /** - * Transliterate using the Transliterator package. - * - * @param string $str Input string (UTF-8). - * - * @return mixed Transliterated string (UTF-8), or false on error. - */ - protected static function _intlToAscii($str) - { - if (class_exists('Transliterator')) { - if (!isset(self::$_transliterator)) { - self::$_transliterator = Transliterator::create( - 'Any-Latin; Latin-ASCII' - ); - } - - if (!is_null(self::$_transliterator)) { - /* Returns false on error. */ - return self::$_transliterator->transliterate($str); - } - } - - return false; - } - - /** - * Transliterate using the iconv extension. - * - * @param string $str Input string (UTF-8). - * - * @return mixed Transliterated string (UTF-8), or false on error. - */ - protected static function _iconvToAscii($str) - { - return extension_loaded('iconv') - /* Returns false on error. */ - ? iconv('UTF-8', 'ASCII//TRANSLIT', $str) - : false; - } - - /** - * Transliterate using a built-in ASCII mapping. - * - * @param string $str Input string (UTF-8). - * - * @return string Transliterated string (UTF-8). - */ - protected static function _fallbackToAscii($str) - { - if (!isset(self::$_map)) { - self::$_map = array( - 'À' => 'A', - 'Á' => 'A', - 'Â' => 'A', - 'Ã' => 'A', - 'Ä' => 'A', - 'Å' => 'A', - 'Æ' => 'AE', - 'à' => 'a', - 'á' => 'a', - 'â' => 'a', - 'ã' => 'a', - 'ä' => 'a', - 'å' => 'a', - 'æ' => 'ae', - 'Þ' => 'TH', - 'þ' => 'th', - 'Ç' => 'C', - 'ç' => 'c', - 'Ð' => 'D', - 'ð' => 'd', - 'È' => 'E', - 'É' => 'E', - 'Ê' => 'E', - 'Ë' => 'E', - 'è' => 'e', - 'é' => 'e', - 'ê' => 'e', - 'ë' => 'e', - 'ƒ' => 'f', - 'Ì' => 'I', - 'Í' => 'I', - 'Î' => 'I', - 'Ï' => 'I', - 'ì' => 'i', - 'í' => 'i', - 'î' => 'i', - 'ï' => 'i', - 'Ñ' => 'N', - 'ñ' => 'n', - 'Ò' => 'O', - 'Ó' => 'O', - 'Ô' => 'O', - 'Õ' => 'O', - 'Ö' => 'O', - 'Ø' => 'O', - 'ò' => 'o', - 'ó' => 'o', - 'ô' => 'o', - 'õ' => 'o', - 'ö' => 'o', - 'ø' => 'o', - 'Š' => 'S', - 'ẞ' => 'SS', - 'ß' => 'ss', - 'š' => 's', - 'ś' => 's', - 'Ù' => 'U', - 'Ú' => 'U', - 'Û' => 'U', - 'Ü' => 'U', - 'ù' => 'u', - 'ú' => 'u', - 'û' => 'u', - 'Ý' => 'Y', - 'ý' => 'y', - 'ÿ' => 'y', - 'Ž' => 'Z', - 'ž' => 'z' - ); - } - - /* This should never return false. */ - return strtr(strval($str), self::$_map); - } -} diff --git a/lib/horde/framework/Horde/Support/Array.php b/lib/horde/framework/Horde/Support/Array.php deleted file mode 100644 index 958e5e78984..00000000000 --- a/lib/horde/framework/Horde/Support/Array.php +++ /dev/null @@ -1,207 +0,0 @@ -update($vars); - } - } - - /** - */ - public function get($key, $default = null) - { - return isset($this->_array[$key]) ? $this->_array[$key] : $default; - } - - /** - * Gets the value at $offset. If no value exists at that offset, or the - * value $offset is NULL, then $default is set as the value of $offset. - * - * @param string $offset Offset to retrieve and set if unset - * @param string $default Default value if $offset does not exist - * - * @return mixed Value at $offset or $default - */ - public function getOrSet($offset, $default = null) - { - $value = $this->offsetGet($offset); - if (is_null($value)) { - $this->offsetSet($offset, $value = $default); - } - return $value; - } - - /** - * Gets the value at $offset and deletes it from the array. If no value - * exists at $offset, or the value at $offset is null, then $default - * will be returned. - * - * @param string $offset Offset to pop - * @param string $default Default value - * - * @return mixed Value at $offset or $default - */ - public function pop($offset, $default = null) - { - $value = $this->offsetGet($offset); - $this->offsetUnset($offset); - return isset($value) ? $value : $default; - } - - /** - * Update the array with the key/value pairs from $array - * - * @param array $array Key/value pairs to set/change in the array. - */ - public function update($array) - { - if (!is_array($array) && !$array instanceof Traversable) { - throw new InvalidArgumentException('expected array or traversable, got ' . gettype($array)); - } - - foreach ($array as $key => $val) { - $this->offsetSet($key, $val); - } - } - - /** - * Get the keys in the array - * - * @return array - */ - public function getKeys() - { - return array_keys($this->_array); - } - - /** - * Get the values in the array - * - * @return array - */ - public function getValues() - { - return array_values($this->_array); - } - - /** - * Clear out the array - */ - public function clear() - { - $this->_array = array(); - } - - /** - */ - public function __get($key) - { - return $this->get($key); - } - - /** - */ - public function __set($key, $value) - { - $this->_array[$key] = $value; - } - - /** - * Checks the existance of $key in this array - */ - public function __isset($key) - { - return array_key_exists($key, $this->_array); - } - - /** - * Removes $key from this array - */ - public function __unset($key) - { - unset($this->_array[$key]); - } - - /** - * Count the number of elements - * - * @return integer - */ - #[ReturnTypeWillChange] - public function count() - { - return count($this->_array); - } - - /** - */ - #[ReturnTypeWillChange] - public function getIterator() - { - return new ArrayIterator($this->_array); - } - - /** - * Gets the value of $offset in this array - * - * @see __get() - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - return $this->__get($offset); - } - - /** - * Sets the value of $offset to $value - * - * @see __set() - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - return $this->__set($offset, $value); - } - - /** - * Checks the existence of $offset in this array - * - * @see __isset() - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) - { - return $this->__isset($offset); - } - - /** - * Removes $offset from this array - * - * @see __unset() - */ - #[ReturnTypeWillChange] - public function offsetUnset($offset) - { - return $this->__unset($offset); - } - -} diff --git a/lib/horde/framework/Horde/Support/Backtrace.php b/lib/horde/framework/Horde/Support/Backtrace.php deleted file mode 100644 index bd04a795f55..00000000000 --- a/lib/horde/framework/Horde/Support/Backtrace.php +++ /dev/null @@ -1,175 +0,0 @@ -createFromThrowable($backtrace); - } elseif ($backtrace instanceof Exception) { - $this->createFromException($backtrace); - } elseif ($backtrace) { - $this->createFromDebugBacktrace($backtrace); - } else { - $this->createFromDebugBacktrace(debug_backtrace(), 1); - } - } - - /** - * Wraps the result of debug_backtrace(). - * - * By specifying a non-zero $nestingLevel, levels of the backtrace can be - * ignored. For instance, when Horde_Support_Backtrace creates a backtrace - * for you, it ignores the Horde_Backtrace constructor in the wrapped - * trace. - * - * @param array $backtrace The debug_backtrace() result. - * @param integer $nestingLevel The number of levels of the backtrace to - * ignore. - */ - public function createFromDebugBacktrace($backtrace, $nestingLevel = 0) - { - while ($nestingLevel > 0) { - array_shift($backtrace); - --$nestingLevel; - } - - $this->backtrace = $backtrace; - } - - /** - * Wraps an error object's backtrace. - * - * @since Horde_Support 2.2.0 - * - * @param Throwable $e The error to wrap. - */ - public function createFromThrowable(Throwable $e) - { - $this->_createFromThrowable($e); - } - - /** - * Wraps an error object's backtrace. - * - * @todo Merge with createFromThrowable with PHP 7. - * - * @param Throwable $e The error to wrap. - */ - protected function _createFromThrowable($e) - { - $this->backtrace = $e->getTrace(); - if ($previous = $e->getPrevious()) { - $backtrace = new self($previous); - $this->backtrace = array_merge($backtrace->backtrace, - $this->backtrace); - } - } - - /** - * Wraps an Exception object's backtrace. - * - * @todo Remove with PHP 7. - * - * @param Exception $e The exception to wrap. - */ - public function createFromException(Exception $e) - { - $this->_createFromThrowable($e); - } - - /** - * Returns the nesting level (number of calls deep) of the current context. - * - * @return integer Nesting level. - */ - public function getNestingLevel() - { - return count($this->backtrace); - } - - /** - * Returns the context at a specific nesting level. - * - * @param integer $nestingLevel 0 == current level, 1 == caller, and so on - * - * @return array The requested context. - */ - public function getContext($nestingLevel) - { - if (!isset($this->backtrace[$nestingLevel])) { - throw new Horde_Exception('Unknown nesting level'); - } - return $this->backtrace[$nestingLevel]; - } - - /** - * Returns details about the routine where the exception occurred. - * - * @return array $caller - */ - public function getCurrentContext() - { - return $this->getContext(0); - } - - /** - * Returns details about the caller of the routine where the exception - * occurred. - * - * @return array $caller - */ - public function getCallingContext() - { - return $this->getContext(1); - } - - /** - * Returns a simple, human-readable list of the complete backtrace. - * - * @return string The backtrace map. - */ - public function __toString() - { - $count = count($this->backtrace); - $pad = strlen($count); - $map = ''; - for ($i = $count - 1; $i >= 0; $i--) { - $map .= str_pad($count - $i, $pad, ' ', STR_PAD_LEFT) . '. '; - if (isset($this->backtrace[$i]['class'])) { - $map .= $this->backtrace[$i]['class'] - . $this->backtrace[$i]['type']; - } - $map .= $this->backtrace[$i]['function'] . '()'; - if (isset($this->backtrace[$i]['file'])) { - $map .= ' ' . $this->backtrace[$i]['file'] - . ':' . $this->backtrace[$i]['line']; - } - $map .= "\n"; - } - return $map; - } -} diff --git a/lib/horde/framework/Horde/Support/CaseInsensitiveArray.php b/lib/horde/framework/Horde/Support/CaseInsensitiveArray.php deleted file mode 100644 index f9fb43de94e..00000000000 --- a/lib/horde/framework/Horde/Support/CaseInsensitiveArray.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @category Horde - * @copyright 2013-2017 Horde LLC - * @license http://www.horde.org/licenses/bsd BSD - * @package Support - */ -class Horde_Support_CaseInsensitiveArray extends ArrayIterator -{ - /** - */ - #[ReturnTypeWillChange] - public function offsetGet($offset) - { - return (is_null($offset = $this->_getRealOffset($offset))) - ? null - : parent::offsetGet($offset); - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - if (is_null($roffset = $this->_getRealOffset($offset))) { - parent::offsetSet($offset, $value); - } else { - parent::offsetSet($roffset, $value); - } - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetExists($offset) - { - return !is_null($offset = $this->_getRealOffset($offset)); - } - - /** - */ - #[ReturnTypeWillChange] - public function offsetUnset($offset) - { - if (!is_null($offset = $this->_getRealOffset($offset))) { - parent::offsetUnset($offset); - } - } - - /** - * Determines the actual array offset given the input offset. - * - * @param string $offset Input offset. - * - * @return string Real offset or null. - */ - protected function _getRealOffset($offset) - { - /* Optimize: check for base $offset in array first. */ - if (parent::offsetExists($offset)) { - return $offset; - } - - foreach (array_keys($this->getArrayCopy()) as $key) { - if (strcasecmp($key, $offset) === 0) { - return $key; - } - } - - return null; - } - -} diff --git a/lib/horde/framework/Horde/Support/CombineStream.php b/lib/horde/framework/Horde/Support/CombineStream.php deleted file mode 100644 index 30e1cb7a88e..00000000000 --- a/lib/horde/framework/Horde/Support/CombineStream.php +++ /dev/null @@ -1,87 +0,0 @@ - - * @license http://www.horde.org/licenses/bsd BSD - * @category Horde - * @package Support - */ - -/** - * Provides access to the Combine stream wrapper. - * - * @author Michael Slusarz - * @license http://www.horde.org/licenses/bsd BSD - * @category Horde - * @deprecated Use Horde_Stream_Wrapper_Combine::getStream() - * @package Support - */ -class Horde_Support_CombineStream implements Horde_Stream_Wrapper_CombineStream -{ - /** - * Data. - * - * @var array - */ - protected $_data; - - /** - * Constructor - * - * @param array $data An array of strings and/or streams to combine into - * a single stream. - */ - public function __construct($data) - { - $this->installWrapper(); - $this->_data = $data; - } - - /** - * Return a stream handle to this stream. - * - * @return resource - */ - public function fopen() - { - $context = stream_context_create(array('horde-combine' => array('data' => $this))); - return fopen('horde-combine://' . spl_object_hash($this), 'rb', false, $context); - } - - /** - * Return an SplFileObject representing this stream - * - * @return SplFileObject - */ - public function getFileObject() - { - $context = stream_context_create(array('horde-combine' => array('data' => $this))); - return new SplFileObject('horde-combine://' . spl_object_hash($this), 'rb', false, $context); - } - - /** - * Install the horde-combine stream wrapper if it isn't already - * registered. - * - * @throws Exception - */ - public function installWrapper() - { - if (!in_array('horde-combine', stream_get_wrappers()) && - !stream_wrapper_register('horde-combine', 'Horde_Stream_Wrapper_Combine')) { - throw new Exception('Unable to register horde-combine stream wrapper.'); - } - } - - /** - * Return a reference to the data. - * - * @return array - */ - public function getData() - { - return $this->_data; - } - -} diff --git a/lib/horde/framework/Horde/Support/ConsistentHash.php b/lib/horde/framework/Horde/Support/ConsistentHash.php deleted file mode 100644 index 98f570bb264..00000000000 --- a/lib/horde/framework/Horde/Support/ConsistentHash.php +++ /dev/null @@ -1,244 +0,0 @@ -_numberOfReplicas = $numberOfReplicas; - $this->addNodes($nodes, $weight); - } - - /** - * Get the primary node for $key. - * - * @param string $key The key to look up. - * - * @param string The primary node for $key. - */ - public function get($key) - { - $nodes = $this->getNodes($key, 1); - if (!$nodes) { - throw new Exception('No nodes found'); - } - return $nodes[0]; - } - - /** - * Get an ordered list of nodes for $key. - * - * @param string $key The key to look up. - * @param integer $count The number of nodes to look up. - * - * @return array An ordered array of nodes. - */ - public function getNodes($key, $count = 5) - { - // Degenerate cases - if ($this->_nodeCount < $count) { - throw new Exception('Not enough nodes (have ' . $this->_nodeCount . ', ' . $count . ' requested)'); - } - if ($this->_nodeCount == 0) { - return array(); - } - - // Simple case - if ($this->_nodeCount == 1) { - return array($this->_nodes[0]['n']); - } - - $hash = $this->hash(serialize($key)); - - // Find the first point on the circle greater than $hash by binary search. - $low = 0; - $high = $this->_pointCount - 1; - $index = null; - while (true) { - $mid = (int)(($low + $high) / 2); - if ($mid == $this->_pointCount) { - $index = 0; - break; - } - - $midval = $this->_pointMap[$mid]; - $midval1 = ($mid == 0) ? 0 : $this->_pointMap[$mid - 1]; - if ($midval1 < $hash && $hash <= $midval) { - $index = $mid; - break; - } - - if ($midval > $hash) { - $high = $mid - 1; - } else { - $low = $mid + 1; - } - - if ($low > $high) { - $index = 0; - break; - } - } - - $nodes = array(); - while (count($nodes) < $count) { - $nodeIndex = $this->_pointMap[$index++ % $this->_pointCount]; - $nodes[$nodeIndex] = $this->_nodes[$this->_circle[$nodeIndex]]['n']; - } - return array_values($nodes); - } - - /** - * Add $node with weight $weight - * - * @param mixed $node - */ - public function add($node, $weight = 1) - { - // Delegate to addNodes so that the circle is only regenerated once when - // adding multiple nodes. - $this->addNodes(array($node), $weight); - } - - /** - * Add multiple nodes to the hash with the same weight. - * - * @param array $nodes An array of nodes. - * @param integer $weight The weight to add the nodes with. - */ - public function addNodes($nodes, $weight = 1) - { - foreach ($nodes as $node) { - $this->_nodes[] = array('n' => $node, 'w' => $weight); - $this->_nodeCount++; - - $nodeIndex = $this->_nodeCount - 1; - $nodeString = serialize($node); - - $numberOfReplicas = (int)($weight * $this->_numberOfReplicas); - for ($i = 0; $i < $numberOfReplicas; $i++) { - $this->_circle[$this->hash($nodeString . $i)] = $nodeIndex; - } - } - - $this->_updateCircle(); - } - - /** - * Remove $node from the hash. - * - * @param mixed $node - */ - public function remove($node) - { - $nodeIndex = null; - $nodeString = serialize($node); - - // Search for the node in the node list - foreach (array_keys($this->_nodes) as $i) { - if ($this->_nodes[$i]['n'] === $node) { - $nodeIndex = $i; - break; - } - } - - if (is_null($nodeIndex)) { - throw new InvalidArgumentException('Node was not in the hash'); - } - - // Remove all points from the circle - $numberOfReplicas = (int)($this->_nodes[$nodeIndex]['w'] * $this->_numberOfReplicas); - for ($i = 0; $i < $numberOfReplicas; $i++) { - unset($this->_circle[$this->hash($nodeString . $i)]); - } - $this->_updateCircle(); - - // Unset the node from the node list - unset($this->_nodes[$nodeIndex]); - $this->_nodeCount--; - } - - /** - * Expose the hash function for testing, probing, and extension. - * - * @param string $key - * - * @return string Hash value - */ - public function hash($key) - { - return 'h' . substr(hash('md5', $key), 0, 8); - } - - /** - * Maintain the circle and arrays of points. - */ - protected function _updateCircle() - { - // Sort the circle - ksort($this->_circle); - - // Now that the hashes are sorted, generate numeric indices into the - // circle. - $this->_pointMap = array_keys($this->_circle); - $this->_pointCount = count($this->_pointMap); - } - -} diff --git a/lib/horde/framework/Horde/Support/Guid.php b/lib/horde/framework/Horde/Support/Guid.php deleted file mode 100644 index a3eae2979b3..00000000000 --- a/lib/horde/framework/Horde/Support/Guid.php +++ /dev/null @@ -1,73 +0,0 @@ - - * $uid = (string)new Horde_Support_Guid([$opts = array()]); - * - * - * Copyright 2009-2017 Horde LLC (http://www.horde.org/) - * - * @category Horde - * @package Support - * @license http://www.horde.org/licenses/bsd - */ -class Horde_Support_Guid -{ - /** - * Generated GUID. - * - * @var string - */ - private $_guid; - - /** - * New GUID. - * - * @param array $opts Additional options: - *
-     * 'prefix' - (string) A prefix to add between the date string and the
-     *            random string.
-     *            DEFAULT: NONE
-     * 'server' - (string) The server name.
-     *            DEFAULT: $_SERVER['SERVER_NAME'] (or 'localhost')
-     * 
- */ - public function __construct(array $opts = array()) - { - $this->generate($opts); - } - - /** - * Generates a GUID. - * - * @param array $opts Additional options: - *
-     * 'prefix' - (string) A prefix to add between the date string and the
-     *            random string.
-     *            DEFAULT: NONE
-     * 'server' - (string) The server name.
-     *            DEFAULT: $_SERVER['SERVER_NAME'] (or 'localhost')
-     * 
- */ - public function generate(array $opts = array()) - { - $this->_guid = date('YmdHis') - . '.' - . (isset($opts['prefix']) ? $opts['prefix'] . '.' : '') - . strval(new Horde_Support_Randomid()) - . '@' - . (isset($opts['server']) ? $opts['server'] : (!empty($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost')); - } - - /** - * Cooerce to string. - * - * @return string - */ - public function __toString() - { - return $this->_guid; - } - -} diff --git a/lib/horde/framework/Horde/Support/Inflector.php b/lib/horde/framework/Horde/Support/Inflector.php deleted file mode 100644 index babdb5e4f07..00000000000 --- a/lib/horde/framework/Horde/Support/Inflector.php +++ /dev/null @@ -1,437 +0,0 @@ - 'moves', - '/sex$/i' => 'sexes', - '/child$/i' => 'children', - '/man$/i' => 'men', - '/foot$/i' => 'feet', - '/person$/i' => 'people', - '/(quiz)$/i' => '$1zes', - '/^(ox)$/i' => '$1en', - '/(m|l)ouse$/i' => '$1ice', - '/(matr|vert|ind)ix|ex$/i' => '$1ices', - '/(x|ch|ss|sh)$/i' => '$1es', - '/([^aeiouy]|qu)ies$/i' => '$1y', - '/([^aeiouy]|qu)y$/i' => '$1ies', - '/(?:([^f])fe|([lr])f)$/i' => '$1$2ves', - '/sis$/i' => 'ses', - '/([ti])um$/i' => '$1a', - '/(buffal|tomat)o$/i' => '$1oes', - '/(bu)s$/i' => '$1ses', - '/(alias|status)$/i' => '$1es', - '/(octop|vir)us$/i' => '$1i', - '/(ax|test)is$/i' => '$1es', - '/s$/i' => 's', - '/$/' => 's', - ); - - /** - * Rules for singularizing English nouns. - * - * @var array - */ - protected $_singularizationRules = array( - '/cookies$/i' => 'cookie', - '/moves$/i' => 'move', - '/sexes$/i' => 'sex', - '/children$/i' => 'child', - '/men$/i' => 'man', - '/feet$/i' => 'foot', - '/people$/i' => 'person', - '/databases$/i'=> 'database', - '/(quiz)zes$/i' => '\1', - '/(matr)ices$/i' => '\1ix', - '/(vert|ind)ices$/i' => '\1ex', - '/^(ox)en/i' => '\1', - '/(alias|status)es$/i' => '\1', - '/([octop|vir])i$/i' => '\1us', - '/(cris|ax|test)es$/i' => '\1is', - '/(shoe)s$/i' => '\1', - '/(o)es$/i' => '\1', - '/(bus)es$/i' => '\1', - '/([m|l])ice$/i' => '\1ouse', - '/(x|ch|ss|sh)es$/i' => '\1', - '/(m)ovies$/i' => '\1ovie', - '/(s)eries$/i' => '\1eries', - '/([^aeiouy]|qu)ies$/i' => '\1y', - '/([lr])ves$/i' => '\1f', - '/(tive)s$/i' => '\1', - '/(hive)s$/i' => '\1', - '/([^f])ves$/i' => '\1fe', - '/(^analy)ses$/i' => '\1sis', - '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis', - '/([ti])a$/i' => '\1um', - '/(n)ews$/i' => '\1ews', - '/(.*)s$/i' => '\1', - ); - - /** - * An array of words with the same singular and plural spellings. - * - * @var array - */ - protected $_uncountables = array( - 'aircraft', - 'cannon', - 'deer', - 'equipment', - 'fish', - 'information', - 'money', - 'moose', - 'rice', - 'series', - 'sheep', - 'species', - 'swine', - ); - - /** - * Constructor. - * - * Stores a map of the uncountable words for quicker checks. - */ - public function __construct() - { - $this->_uncountables_keys = array_flip($this->_uncountables); - } - - /** - * Adds an uncountable word. - * - * @param string $word The uncountable word. - */ - public function uncountable($word) - { - $this->_uncountables[] = $word; - $this->_uncountables_keys[$word] = true; - } - - /** - * Singular English word to pluralize. - * - * @param string $word Word to pluralize. - * - * @return string Plural form of $word. - */ - public function pluralize($word) - { - if ($plural = $this->getCache($word, 'pluralize')) { - return $plural; - } - - if (isset($this->_uncountables_keys[$word])) { - return $word; - } - - foreach ($this->_pluralizationRules as $regexp => $replacement) { - $plural = preg_replace($regexp, $replacement, $word, -1, $matches); - if ($matches > 0) { - return $this->setCache($word, 'pluralize', $plural); - } - } - - return $this->setCache($word, 'pluralize', $word); - } - - /** - * Plural English word to singularize. - * - * @param string $word Word to singularize. - * - * @return string Singular form of $word. - */ - public function singularize($word) - { - if ($singular = $this->getCache($word, 'singularize')) { - return $singular; - } - - if (isset($this->_uncountables_keys[$word])) { - return $word; - } - - foreach ($this->_singularizationRules as $regexp => $replacement) { - $singular = preg_replace($regexp, $replacement, $word, -1, $matches); - if ($matches > 0) { - return $this->setCache($word, 'singularize', $singular); - } - } - - return $this->setCache($word, 'singularize', $word); - } - - /** - * Camel-cases a word. - * - * @todo Do we want locale-specific or locale-independent camel casing? - * - * @param string $word The word to camel-case. - * @param string $firstLetter Whether to upper or lower case the first. - * letter of each slash-separated section. - * - * @return string Camelized $word - */ - public function camelize($word, $firstLetter = 'upper') - { - if ($camelized = $this->getCache($word, 'camelize' . $firstLetter)) { - return $camelized; - } - - $camelized = $word; - if (Horde_String::lower($camelized) != $camelized && - strpos($camelized, '_') !== false) { - $camelized = str_replace('_', '/', $camelized); - } - if (strpos($camelized, '/') !== false) { - $camelized = str_replace('/', '/ ', $camelized); - } - if (strpos($camelized, '_') !== false) { - $camelized = strtr($camelized, '_', ' '); - } - - $camelized = str_replace(' ', '', Horde_String::ucwords($camelized)); - - if ($firstLetter == 'lower') { - $parts = array(); - foreach (explode('/', $camelized) as $part) { - $part[0] = Horde_String::lower($part[0]); - $parts[] = $part; - } - $camelized = implode('/', $parts); - } - - return $this->setCache($word, 'camelize' . $firstLetter, $camelized); - } - - /** - * Capitalizes all the words and replaces some characters in the string to - * create a nicer looking title. - * - * Titleize is meant for creating pretty output. - * - * See: - * - http://daringfireball.net/2008/05/title_case - * - http://daringfireball.net/2008/08/title_case_update - * - * Examples: - * 1. titleize("man from the boondocks") => "Man From The Boondocks" - * 2. titleize("x-men: the last stand") => "X Men: The Last Stand" - */ - public function titleize($word) - { - throw new Exception('not implemented yet'); - } - - /** - * The reverse of camelize(). - * - * Makes an underscored form from the expression in the string. - * - * Examples: - * 1. underscore("ActiveRecord") => "active_record" - * 2. underscore("ActiveRecord_Errors") => "active_record_errors" - * - * @todo Do we want locale-specific or locale-independent lowercasing? - */ - public function underscore($camelCasedWord) - { - $word = $camelCasedWord; - if ($result = $this->getCache($word, 'underscore')) { - return $result; - } - $result = Horde_String::lower(preg_replace('/([a-z])([A-Z])/', "\${1}_\${2}", $word)); - return $this->setCache($word, 'underscore', $result); - } - - /** - * Replaces underscores with dashes in the string. - * - * Example: - * 1. dasherize("puni_puni") => "puni-puni" - */ - public function dasherize($underscoredWord) - { - if ($result = $this->getCache($underscoredWord, 'dasherize')) { - return $result; - } - - $result = str_replace('_', '-', $this->underscore($underscoredWord)); - return $this->setCache($underscoredWord, 'dasherize', $result); - } - - /** - * Capitalizes the first word and turns underscores into spaces and strips - * _id. - * - * Like titleize(), this is meant for creating pretty output. - * - * Examples: - * 1. humanize("employee_salary") => "Employee salary" - * 2. humanize("author_id") => "Author" - */ - public function humanize($lowerCaseAndUnderscoredWord) - { - $word = $lowerCaseAndUnderscoredWord; - if ($result = $this->getCache($word, 'humanize')) { - return $result; - } - - $result = ucfirst(str_replace('_', ' ', $this->underscore($word))); - if (substr($result, -3, 3) == ' id') { - $result = str_replace(' id', '', $result); - } - return $this->setCache($word, 'humanize', $result); - } - - /** - * Removes the module part from the expression in the string. - * - * Examples: - * 1. demodulize("Fax_Job") => "Job" - * 1. demodulize("User") => "User" - */ - public function demodulize($classNameInModule) - { - $result = explode('_', $classNameInModule); - return array_pop($result); - } - - /** - * Creates the name of a table like Rails does for models to table names. - * - * This method uses the pluralize() method on the last word in the string. - * - * Examples: - * 1. tableize("RawScaledScorer") => "raw_scaled_scorers" - * 2. tableize("egg_and_ham") => "egg_and_hams" - * 3. tableize("fancyCategory") => "fancy_categories" - */ - public function tableize($className) - { - if ($result = $this->getCache($className, 'tableize')) { - return $result; - } - - $result = $this->pluralize($this->underscore($className)); - $result = str_replace('/', '_', $result); - return $this->setCache($className, 'tableize', $result); - } - - /** - * Creates a class name from a table name like Rails does for table names - * to models. - * - * Examples: - * 1. classify("egg_and_hams") => "EggAndHam" - * 2. classify("post") => "Post" - */ - public function classify($tableName) - { - if ($result = $this->getCache($tableName, 'classify')) { - return $result; - } - $result = $this->camelize($this->singularize($tableName)); - - // classes use underscores instead of slashes for namespaces - $result = str_replace('/', '_', $result); - return $this->setCache($tableName, 'classify', $result); - } - - /** - * Creates a foreign key name from a class name. - * - * $separateClassNameAndIdWithUnderscore sets whether the method should put - * '_' between the name and 'id'. - * - * Examples: - * 1. foreignKey("Message") => "message_id" - * 2. foreignKey("Message", false) => "messageid" - * 3. foreignKey("Fax_Job") => "fax_job_id" - */ - public function foreignKey($className, $separateClassNameAndIdWithUnderscore = true) - { - throw new Exception('not implemented yet'); - } - - /** - * Turns a number into an ordinal string used to denote the position in an - * ordered sequence such as 1st, 2nd, 3rd, 4th. - * - * Examples: - * 1. ordinalize(1) => "1st" - * 2. ordinalize(2) => "2nd" - * 3. ordinalize(1002) => "1002nd" - * 4. ordinalize(1003) => "1003rd" - */ - public function ordinalize($number) - { - throw new Exception('not implemented yet'); - } - - /** - * Clears the inflection cache. - */ - public function clearCache() - { - $this->_cache = array(); - } - - /** - * Retuns a cached inflection. - * - * @return string | false - */ - public function getCache($word, $rule) - { - return isset($this->_cache[$word . '|' . $rule]) ? - $this->_cache[$word . '|' . $rule] : false; - } - - /** - * Caches an inflection. - * - * @param string $word The word being inflected. - * @param string $rule The inflection rule. - * @param string $value The inflected value of $word. - * - * @return string The inflected value - */ - public function setCache($word, $rule, $value) - { - $this->_cache[$word . '|' . $rule] = $value; - return $value; - } -} diff --git a/lib/horde/framework/Horde/Support/Memory.php b/lib/horde/framework/Horde/Support/Memory.php deleted file mode 100644 index 1389858c25a..00000000000 --- a/lib/horde/framework/Horde/Support/Memory.php +++ /dev/null @@ -1,84 +0,0 @@ - - * $t = new Horde_Support_Memory; - * $t->push(); - * $used = $t->pop(); - * - * - * Do not expect too much of this memory tracker. Profiling memory is not - * trivial as your placement of the measurements may obscure important - * information. As a trivial example: Assuming that your script used 20 MB of - * memory befory you call push() the information you get when calling pop() - * might only tell you that there was less than 20 MB of memory consumed in - * between the two calls. Take the changes to internal memory handling of PHP in - * between the different versions into account - * (http://de3.php.net/manual/en/features.gc.performance-considerations.php) and - * you should get an idea about why you might be cautious about the values you - * get from this memory tracker. - * - * Copyright 2011-2017 Horde LLC (http://www.horde.org/) - * - * @category Horde - * @package Support - * @license http://www.horde.org/licenses/bsd - */ -class Horde_Support_Memory -{ - /** - * Holds the starting memory consumption. - * - * @var array - */ - protected $_start = array(); - - /** - * Current index for stacked trackers. - * - * @var integer - */ - protected $_idx = 0; - - /** - * Push a new tracker on the stack. - */ - public function push() - { - $start = $this->_start[$this->_idx++] = array( - memory_get_usage(), - memory_get_peak_usage(), - memory_get_usage(true), - memory_get_peak_usage(true) - ); - return $start; - } - - /** - * Pop the latest tracker and return the difference with the current - * memory situation. - * - * @return array The change in memory allocated via emalloc() in between the - * push() and the pop() call. The array holds four values: the - * first one indicates the change in current usage of memory - * while the second value indicates any changes in the peak - * amount of memory used. The third and fourth value show - * current and peak usage as well but indicate the real memory - * usage and not just the part allocated via emalloc(), - */ - public function pop() - { - if (! ($this->_idx > 0)) { - throw new Exception('No timers have been started'); - } - $start = $this->_start[--$this->_idx]; - return array( - memory_get_usage() - $start[0], - memory_get_peak_usage() - $start[1], - memory_get_usage(true) - $start[2], - memory_get_peak_usage(true) - $start[3] - ); - } - -} diff --git a/lib/horde/framework/Horde/Support/Numerizer.php b/lib/horde/framework/Horde/Support/Numerizer.php deleted file mode 100644 index 94e23f85e17..00000000000 --- a/lib/horde/framework/Horde/Support/Numerizer.php +++ /dev/null @@ -1,46 +0,0 @@ - - * @license http://www.horde.org/licenses/bsd BSD - * @category Horde - * @package Support - */ - -/** - * @author Chuck Hagenbuch - * @license http://www.horde.org/licenses/bsd BSD - * @category Horde - * @package Support - */ -class Horde_Support_Numerizer -{ - public static function numerize($string, $args = array()) - { - return self::factory($args)->numerize($string); - } - - public static function factory($args = array()) - { - $locale = isset($args['locale']) ? $args['locale'] : null; - if ($locale && Horde_String::lower($locale) != 'base') { - $locale = str_replace(' ', '_', Horde_String::ucwords(str_replace('_', ' ', Horde_String::lower($locale)))); - $class = 'Horde_Support_Numerizer_Locale_' . $locale; - if (class_exists($class)) { - return new $class($args); - } - - list($language,) = explode('_', $locale); - if ($language != $locale) { - $class = 'Horde_Support_Numerizer_Locale_' . $language; - if (class_exists($class)) { - return new $class($args); - } - } - } - - return new Horde_Support_Numerizer_Locale_Base($args); - } - -} diff --git a/lib/horde/framework/Horde/Support/Numerizer/Locale/Base.php b/lib/horde/framework/Horde/Support/Numerizer/Locale/Base.php deleted file mode 100644 index ab46f429a8e..00000000000 --- a/lib/horde/framework/Horde/Support/Numerizer/Locale/Base.php +++ /dev/null @@ -1,166 +0,0 @@ - - * @license http://www.horde.org/licenses/bsd BSD - * @category Horde - * @package Support - */ - -/** - * @author Chuck Hagenbuch - * @license http://www.horde.org/licenses/bsd BSD - * @category Horde - * @package Support - */ -class Horde_Support_Numerizer_Locale_Base -{ - public $DIRECT_NUMS = array( - 'eleven' => '11', - 'twelve' => '12', - 'thirteen' => '13', - 'fourteen' => '14', - 'fifteen' => '15', - 'sixteen' => '16', - 'seventeen' => '17', - 'eighteen' => '18', - 'nineteen' => '19', - 'ninteen' => '19', // Common mis-spelling - 'zero' => '0', - 'one' => '1', - 'two' => '2', - 'three' => '3', - 'four(\W|$)' => '4$1', // The weird regex is so that it matches four but not fourty - 'five' => '5', - 'six(\W|$)' => '6$1', - 'seven(\W|$)' => '7$1', - 'eight(\W|$)' => '8$1', - 'nine(\W|$)' => '9$1', - 'ten' => '10', - '\ba[\b^$]' => '1', // doesn't make sense for an 'a' at the end to be a 1 - ); - - public $TEN_PREFIXES = array( - 'twenty' => 20, - 'thirty' => 30, - 'forty' => 40, - 'fourty' => 40, // Common mis-spelling - 'fifty' => 50, - 'sixty' => 60, - 'seventy' => 70, - 'eighty' => 80, - 'ninety' => 90, - 'ninty' => 90, // Common mis-spelling - ); - - public $BIG_PREFIXES = array( - 'hundred' => 100, - 'thousand' => 1000, - 'million' => 1000000, - 'billion' => 1000000000, - 'trillion' => 1000000000000, - ); - - public function numerize($string) - { - // preprocess - $string = $this->_splitHyphenatedWords($string); - $string = $this->_hideAHalf($string); - - $string = $this->_directReplacements($string); - $string = $this->_replaceTenPrefixes($string); - $string = $this->_replaceBigPrefixes($string); - $string = $this->_fractionalAddition($string); - - return $string; - } - - /** - * will mutilate hyphenated-words but shouldn't matter for date extraction - */ - protected function _splitHyphenatedWords($string) - { - return preg_replace('/ +|([^\d])-([^d])/', '$1 $2', $string); - } - - /** - * take the 'a' out so it doesn't turn into a 1, save the half for the end - */ - protected function _hideAHalf($string) - { - return str_replace('a half', 'haAlf', $string); - } - - /** - * easy/direct replacements - */ - protected function _directReplacements($string) - { - foreach ($this->DIRECT_NUMS as $dn => $dn_replacement) { - $string = preg_replace("/$dn/i", $dn_replacement, $string); - } - return $string; - } - - /** - * ten, twenty, etc. - */ - protected function _replaceTenPrefixes($string) - { - foreach ($this->TEN_PREFIXES as $tp => $tp_replacement) { - $string = preg_replace_callback( - "/(?:$tp)( *\d(?=[^\d]|\$))*/i", - function ($m) use ($tp_replacement) { - return $tp_replacement + (isset($m[1]) ? (int)$m[1] : 0); - }, - $string - ); - } - return $string; - } - - /** - * hundreds, thousands, millions, etc. - */ - protected function _replaceBigPrefixes($string) - { - foreach ($this->BIG_PREFIXES as $bp => $bp_replacement) { - $string = preg_replace_callback( - '/(\d*) *' . $bp . '/i', - function ($m) use ($bp_replacement) { - return $bp_replacement * (int)$m[1]; - }, - $string - ); - $string = $this->_andition($string); - } - return $string; - } - - protected function _andition($string) - { - while (true) { - if (preg_match('/(\d+)( | and )(\d+)(?=[^\w]|$)/i', $string, $sc, PREG_OFFSET_CAPTURE)) { - if (preg_match('/and/', $sc[2][0]) || (strlen($sc[1][0]) > strlen($sc[3][0]))) { - $string = substr($string, 0, $sc[1][1]) . ((int)$sc[1][0] + (int)$sc[3][0]) . substr($string, $sc[3][1] + strlen($sc[3][0])); - continue; - } - } - break; - } - return $string; - } - - protected function _fractionalAddition($string) - { - return preg_replace_callback( - '/(\d+)(?: | and |-)*haAlf/i', - function ($m) { - return (string)((float)$m[1] + 0.5); - }, - $string - ); - } - -} diff --git a/lib/horde/framework/Horde/Support/Numerizer/Locale/De.php b/lib/horde/framework/Horde/Support/Numerizer/Locale/De.php deleted file mode 100644 index 2b953c8a63d..00000000000 --- a/lib/horde/framework/Horde/Support/Numerizer/Locale/De.php +++ /dev/null @@ -1,132 +0,0 @@ - - * @author Jan Schneider - * @license http://www.horde.org/licenses/bsd BSD - * @category Horde - * @package Support - */ - -/** - * @author Chuck Hagenbuch - * @author Jan Schneider - * @license http://www.horde.org/licenses/bsd BSD - * @category Horde - * @package Support - */ -class Horde_Support_Numerizer_Locale_De extends Horde_Support_Numerizer_Locale_Base -{ - public $DIRECT_NUMS = array( - 'dreizehn' => 13, - 'vierzehn' => 14, - 'fünfzehn' => 15, - 'sechzehn' => 16, - 'siebzehn' => 17, - 'achtzehn' => 18, - 'neunzehn' => 19, - 'ein[se]?' => 1, - 'zwei' => 2, - 'zwo' => 2, - 'drei' => 3, - 'vier' => 4, - 'fünf' => 5, - 'sechs' => 6, - 'sieben' => 7, - 'acht' => 8, - 'neun' => 9, - 'zehn' => 10, - 'elf' => 11, - 'zwölf' => 12, - ); - - public $TEN_PREFIXES = array( - 'zwanzig' => 20, - 'dreißig' => 30, - 'vierzig' => 40, - 'fünfzig' => 50, - 'sechzig' => 60, - 'siebzig' => 70, - 'achtzig' => 80, - 'neunzig' => 90, - ); - - public $BIG_PREFIXES = array( - 'hundert' => 100, - 'tausend' => 1000, - 'million *' => 1000000, - 'milliarde *' => 1000000000, - 'billion *' => 1000000000000, - ); - - /** - * Rules: - * - * - there are irregular word for 11 and 12 like in English - * - numbers below one million are written together (1 M = "eine Million", 100 = "einhundert") - * - "a" is declinable (see above, "one" = "eins", "a" = "ein/eine") - * - numbers below 100 are flipped compared to english, and have an "and = "und" (21 = "twenty-one" = "einundzwanzig") - */ - public function numerize($string) - { - $string = $this->_replaceTenPrefixes($string); - $string = $this->_directReplacements($string); - $string = $this->_replaceBigPrefixes($string); - $string = $this->_fractionalAddition($string); - - return $string; - } - - /** - * ten, twenty, etc. - */ - protected function _replaceTenPrefixes($string) - { - foreach ($this->TEN_PREFIXES as $tp => $tp_replacement) { - $string = preg_replace_callback( - "/(?:$tp)( *\d(?=[^\d]|\$))*/i", - function ($m) use ($tp_replacement) { - return $tp_replacement + (isset($m[1]) ? (int)$m[1] : 0); - }, - $string - ); - } - return $string; - } - - /** - * hundreds, thousands, millions, etc. - */ - protected function _replaceBigPrefixes($string) - { - foreach ($this->BIG_PREFIXES as $bp => $bp_replacement) { - $string = preg_replace_callback( - '/(\d*) *' . $bp . '(\d?)/i', - function ($m) use ($bp_replacement) { - $factor = (int)$m[1]; - if (!$factor) { - $factor = 1; - } - return ($bp_replacement * $factor) - . ($bp_replacement == 100 ? ($m[2] ? 'und' : '') : 'und') - . $m[2]; - }, - $string - ); - $string = $this->_andition($string); - } - return $string; - } - - protected function _andition($string) - { - while (preg_match('/(\d+)((?: *und *)+)(\d*)(?=\w|$)/i', $string, $sc, PREG_OFFSET_CAPTURE)) { - $string = substr($string, 0, $sc[1][1]) - . ((int)$sc[1][0] + (int)$sc[3][0]) - . substr($string, $sc[3][1] + strlen($sc[3][0])); - } - return $string; - } - -} diff --git a/lib/horde/framework/Horde/Support/Numerizer/Locale/Pt.php b/lib/horde/framework/Horde/Support/Numerizer/Locale/Pt.php deleted file mode 100644 index cf590c8f125..00000000000 --- a/lib/horde/framework/Horde/Support/Numerizer/Locale/Pt.php +++ /dev/null @@ -1,152 +0,0 @@ - '13', - 'catorze' => '14', - 'quatorze' => '14', - 'quinze' => '15', - 'dezasseis' => '16', - 'dezassete' => '17', - 'dezoito' => '18', - 'dezanove' => '19', - 'um(\W|$)' => '1$1', - 'uma(\W|$)' => '1$1', - 'dois' => '2', - 'duas' => '2', - 'tres' => '3', - 'quatro' => '4', - 'cinco' => '5', - 'seis' => '6', - 'sete' => '7', - 'oito' => '8', - 'nove' => '9', - 'dez' => '10', - 'onze' => '11', - 'doze' => '12', - ); - - public $TEN_PREFIXES = array( - 'vinte' => '20', - 'trinta' => '30', - 'quarenta' => '40', - 'cinquenta' => '50', - 'sessenta' => '60', - 'setenta' => '70', - 'oitenta' => '80', - 'noventa' => '90', - ); - - public $BIG_PREFIXES = array( - 'cem' => '100', - 'mil' => '1000', - 'milhao *' => '1000000', - 'milhar de *' => '1000000000', - 'biliao *' => '1000000000000', - ); - - public function numerize($string) - { - // preprocess - $string = $this->_splitHyphenateWords($string); - $string = $this->_replaceTenPrefixes($string); - $string = $this->_directReplacements($string); - $string = $this->_replaceBigPrefixes($string); -// $string = $this->_fractionalAddition($string); - - return $string; - } - - - /** - * will mutilate hyphenated-words but shouldn't matter for date extraction - */ - protected function _splitHyphenateWords($string) - { - return preg_replace('/ +|([^\d]) e? ([^d])/', '$1 $2', $string); - } - - /** - * easy/direct replacements - */ - protected function _directReplacements($string) - { - foreach ($this->DIRECT_NUMS as $dn => $dn_replacement) { - $string = preg_replace("/$dn/i", $dn_replacement, $string); - } - return $string; - } - - /** - * ten, twenty, etc. - */ - protected function _replaceTenPrefixes($string) - { - foreach ($this->TEN_PREFIXES as $tp => $tp_replacement) { - $string = preg_replace_callback( - "/(?:$tp)( *\d(?=[^\d]|\$))*/i", - function ($m) use ($tp_replacement) { - return $tp_replacement + (isset($m[1]) ? (int)$m[1] : 0); - }, - $string - ); - } - return $string; - } - - /** - * hundreds, thousands, millions, etc. - */ - protected function _replaceBigPrefixes($string) - { - foreach ($this->BIG_PREFIXES as $bp => $bp_replacement) { - $string = preg_replace_callback( - '/(\d*) *' . $bp . '(\d?)/i', - function ($m) use ($bp_replacement) { - $factor = (int)$m[1]; - if (!$factor) { - $factor = 1; - } - return ($bp_replacement * $factor) - . ($bp_replacement == 100 ? ($m[2] ? 'e' : '') : 'e') - . $m[2]; - }, - $string); - $string = $this->_andition($string); - } - return $string; - } - - protected function _andition($string) - { - while (preg_match('/(\d+)((?: *e *)+)(\d*)(?=\w|$)/i', $string, $sc, PREG_OFFSET_CAPTURE)) { - $string = substr($string, 0, $sc[1][1]) . ((int)$sc[1][0] + (int)$sc[3][0]) . substr($string, $sc[3][1] + strlen($sc[3][0])); - } - return $string; - } - - protected function _fractionalAddition($string) - { - return preg_replace_callback( - '/(\d+)(?: | e |-)*/i', - function ($m) { - return (string)((float)$m[1] + 0.5); - }, - $string - ); - } - -} diff --git a/lib/horde/framework/Horde/Support/ObjectStub.php b/lib/horde/framework/Horde/Support/ObjectStub.php deleted file mode 100644 index d46bba65044..00000000000 --- a/lib/horde/framework/Horde/Support/ObjectStub.php +++ /dev/null @@ -1,69 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/bsd BSD - * @package Support - */ - -/** - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/bsd BSD - * @package Support - */ -class Horde_Support_ObjectStub -{ - /** - * Original data object. - * - * @var array - */ - protected $_data; - - /** - * Constructor - * - * @param object $data The original data object. - */ - public function __construct($data) - { - $this->_data = $data; - } - - /** - */ - public function __get($name) - { - return isset($this->_data->$name) - ? $this->_data->$name - : null; - } - - /** - */ - public function __set($name, $value) - { - $this->_data->$name = $value; - } - - /** - */ - public function __isset($name) - { - return isset($this->_data->$name); - } - - /** - */ - public function __unset($name) - { - unset($this->_data->$name); - } - -} diff --git a/lib/horde/framework/Horde/Support/Randomid.php b/lib/horde/framework/Horde/Support/Randomid.php deleted file mode 100644 index 8be7e1afb82..00000000000 --- a/lib/horde/framework/Horde/Support/Randomid.php +++ /dev/null @@ -1,77 +0,0 @@ - - * $id = (string)new Horde_Support_Randomid(); - * - * - * Copyright 2010-2017 Horde LLC (http://www.horde.org/) - * - * @author Michael Slusarz - * @category Horde - * @license http://www.horde.org/licenses/bsd BSD - * @package Support - */ -class Horde_Support_Randomid -{ - /** - * Generated ID. - * - * @var string - */ - private $_id; - - /** - * New random ID. - */ - public function __construct() - { - $this->_id = $this->generate(); - } - - /** - * Generate a random ID. - */ - public function generate() - { - $elts = array( - uniqid(), - mt_rand(), - getmypid(), - spl_object_hash($this) - ); - if (function_exists('zend_thread_id')) { - $elts[] = zend_thread_id(); - } - if (function_exists('sys_getloadavg') && - ($loadavg = sys_getloadavg())) { - $elts = array_merge($elts, $loadavg); - } - if (function_exists('memory_get_usage')) { - $elts[] = memory_get_usage(); - $elts[] = memory_get_peak_usage(); - } - - shuffle($elts); - - /* Base64 can have /, +, and = characters. Restrict to URL-safe - * characters. */ - return substr(str_replace( - array('/', '+', '='), - array('-', '_', ''), - base64_encode(hash('sha1', serialize($elts), true)) - ), 0, 23); - } - - /** - * Cooerce to string. - * - * @return string The random ID. - */ - public function __toString() - { - return $this->_id; - } -} diff --git a/lib/horde/framework/Horde/Support/Stack.php b/lib/horde/framework/Horde/Support/Stack.php deleted file mode 100644 index d4d8c859ca7..00000000000 --- a/lib/horde/framework/Horde/Support/Stack.php +++ /dev/null @@ -1,41 +0,0 @@ -_stack = $stack; - } - - public function push($value) - { - $this->_stack[] = $value; - } - - public function pop() - { - return array_pop($this->_stack); - } - - public function peek($offset = 1) - { - if (isset($this->_stack[count($this->_stack) - $offset])) { - return $this->_stack[count($this->_stack) - $offset]; - } else { - return null; - } - } -} diff --git a/lib/horde/framework/Horde/Support/StringStream.php b/lib/horde/framework/Horde/Support/StringStream.php deleted file mode 100644 index 1811bc0c8ed..00000000000 --- a/lib/horde/framework/Horde/Support/StringStream.php +++ /dev/null @@ -1,100 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/bsd BSD - * @package Support - */ - -/** - * @author Chuck Hagenbuch - * @category Horde - * @deprecated Use Horde_Stream_Wrapper_String::getStream() - * @license http://www.horde.org/licenses/bsd BSD - * @package Support - */ -class Horde_Support_StringStream implements Horde_Stream_Wrapper_StringStream -{ - /* Wrapper name. */ - const WNAME = 'horde-string'; - - /** - * String data. - * - * @var string - */ - protected $_string; - - /** - * Constructor - * - * @param string &$string Reference to the string to wrap as a stream - */ - public function __construct(&$string) - { - $this->installWrapper(); - $this->_string =& $string; - } - - /** - * Return a stream handle to this string stream. - * - * @return resource - */ - public function fopen() - { - return fopen( - self::WNAME . '://' . spl_object_hash($this), - 'rb', - false, - stream_context_create(array( - self::WNAME => array( - 'string' => $this - ) - )) - ); - } - - /** - * Return an SplFileObject representing this string stream - * - * @return SplFileObject - */ - public function getFileObject() - { - return new SplFileObject( - self::WNAME . '://' . spl_object_hash($this), - 'rb', - false, - stream_context_create(array( - self::WNAME => array( - 'string' => $this - ) - )) - ); - } - - /** - * Install the stream wrapper if it isn't already registered. - */ - public function installWrapper() - { - if (!in_array(self::WNAME, stream_get_wrappers()) && - !stream_wrapper_register(self::WNAME, 'Horde_Stream_Wrapper_String')) { - throw new Exception('Unable to register stream wrapper.'); - } - } - - /** - * Return a reference to the wrapped string. - * - * @return string - */ - public function &getString() - { - return $this->_string; - } - -} diff --git a/lib/horde/framework/Horde/Support/Stub.php b/lib/horde/framework/Horde/Support/Stub.php deleted file mode 100644 index dbb3206f2ec..00000000000 --- a/lib/horde/framework/Horde/Support/Stub.php +++ /dev/null @@ -1,146 +0,0 @@ - - * $t = new Horde_Support_Timer; - * $t->push(); - * $elapsed = $t->pop(); - * - * - * Copyright 1999-2017 Horde LLC (http://www.horde.org/) - * - * @category Horde - * @package Support - * @license http://www.horde.org/licenses/bsd - */ -class Horde_Support_Timer -{ - /** - * Holds the starting timestamp. - * - * @var array - */ - protected $_start = array(); - - /** - * Current index for stacked timers. - * - * @var integer - */ - protected $_idx = 0; - - /** - * Push a new timer start on the stack. - */ - public function push() - { - $start = $this->_start[$this->_idx++] = microtime(true); - return $start; - } - - /** - * Pop the latest timer start and return the difference with the current - * time. - * - * @return float The amount of time passed. - */ - public function pop() - { - $etime = microtime(true); - - if (! ($this->_idx > 0)) { - throw new Exception('No timers have been started'); - } - - return $etime - $this->_start[--$this->_idx]; - } - -} diff --git a/lib/horde/framework/Horde/Support/Uuid.php b/lib/horde/framework/Horde/Support/Uuid.php deleted file mode 100644 index 3a32ec51ef2..00000000000 --- a/lib/horde/framework/Horde/Support/Uuid.php +++ /dev/null @@ -1,85 +0,0 @@ - - * $uuid = (string)new Horde_Support_Uuid; - * - * - * Copyright 2008-2017 Horde LLC (http://www.horde.org/) - * - * @category Horde - * @package Support - * @license http://www.horde.org/licenses/bsd - */ -class Horde_Support_Uuid -{ - /** - * Generated UUID - * @var string - */ - private $_uuid; - - /** - * New UUID. - */ - public function __construct() - { - $this->generate(); - } - - /** - * Generate a 36-character RFC 4122 UUID, without the urn:uuid: prefix. - * - * @see http://www.ietf.org/rfc/rfc4122.txt - * @see http://labs.omniti.com/alexandria/trunk/OmniTI/Util/UUID.php - */ - public function generate() - { - $this->_uuid = null; - if (extension_loaded('uuid')) { - if (function_exists('uuid_export')) { - // UUID extension from http://www.ossp.org/pkg/lib/uuid/ - if (uuid_create($ctx) == UUID_RC_OK && - uuid_make($ctx, UUID_MAKE_V4) == UUID_RC_OK && - uuid_export($ctx, UUID_FMT_STR, $str) == UUID_RC_OK) { - $this->_uuid = $str; - uuid_destroy($ctx); - } - } else { - // UUID extension from http://pecl.php.net/package/uuid - $this->_uuid = uuid_create(); - } - } - if (!$this->_uuid) { - list($time_mid, $time_low) = explode(' ', microtime()); - $time_low = (int)$time_low; - $time_mid = (int)substr($time_mid, 2) & 0xffff; - $time_high = mt_rand(0, 0x0fff) | 0x4000; - - $clock = mt_rand(0, 0x3fff) | 0x8000; - - $node_low = function_exists('zend_thread_id') - ? zend_thread_id() - : getmypid(); - $node_high = isset($_SERVER['SERVER_ADDR']) - ? ip2long($_SERVER['SERVER_ADDR']) - : crc32(php_uname()); - $node = bin2hex(pack('nN', $node_low, $node_high)); - - $this->_uuid = sprintf('%08x-%04x-%04x-%04x-%s', - $time_low, $time_mid, $time_high, $clock, $node); - } - } - - /** - * Cooerce to string. - * - * @return string UUID. - */ - public function __toString() - { - return $this->_uuid; - } - -} diff --git a/lib/horde/framework/Horde/Text/Flowed.php b/lib/horde/framework/Horde/Text/Flowed.php deleted file mode 100644 index e1d74f81e44..00000000000 --- a/lib/horde/framework/Horde/Text/Flowed.php +++ /dev/null @@ -1,376 +0,0 @@ - - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Text_Flowed - */ -class Horde_Text_Flowed -{ - /** - * The maximum length that a line is allowed to be (unless faced with - * with a word that is unreasonably long). This class will re-wrap a - * line if it exceeds this length. - * - * @var integer - */ - protected $_maxlength = 78; - - /** - * When this class wraps a line, the newly created lines will be split - * at this length. - * - * @var integer - */ - protected $_optlength = 72; - - /** - * The text to be formatted. - * - * @var string - */ - protected $_text; - - /** - * The cached output of the formatting. - * - * @var array - */ - protected $_output = array(); - - /** - * The format of the data in $_output. - * - * @var string - */ - protected $_formattype = null; - - /** - * The character set of the text. - * - * @var string - */ - protected $_charset; - - /** - * Convert text using DelSp? - * - * @var boolean - */ - protected $_delsp = false; - - /** - * Constructor. - * - * @param string $text The text to process. - * @param string $charset The character set of $text. - */ - public function __construct($text, $charset = 'UTF-8') - { - $this->_text = $text; - $this->_charset = $charset; - } - - /** - * Set the maximum length of a line of text. - * - * @param integer $max A new value for $_maxlength. - */ - public function setMaxLength($max) - { - $this->_maxlength = $max; - } - - /** - * Set the optimal length of a line of text. - * - * @param integer $max A new value for $_optlength. - */ - public function setOptLength($opt) - { - $this->_optlength = $opt; - } - - /** - * Set whether to format text using DelSp. - * - * @param boolean $delsp Use DelSp? - */ - public function setDelSp($delsp) - { - $this->_delsp = (bool)$delsp; - } - - /** - * Reformats the input string, where the string is 'format=flowed' plain - * text as described in RFC 2646. - * - * @param boolean $quote Add level of quoting to each line? - * - * @return string The text converted to RFC 2646 'fixed' format. - */ - public function toFixed($quote = false) - { - $txt = ''; - - $this->_reformat(false, $quote); - $lines = count($this->_output) - 1; - foreach ($this->_output as $no => $line) { - $txt .= $line['text'] . (($lines == $no) ? '' : "\n"); - } - - return $txt; - } - - /** - * Reformats the input string, and returns the output in an array format - * with quote level information. - * - * @param boolean $quote Add level of quoting to each line? - * - * @return array An array of arrays with the following elements: - *
-     * 'level' - The quote level of the current line.
-     * 'text'  - The text for the current line.
-     * 
- */ - public function toFixedArray($quote = false) - { - $this->_reformat(false, $quote); - return $this->_output; - } - - /** - * Reformats the input string, where the string is 'format=fixed' plain - * text as described in RFC 2646. - * - * @param boolean $quote Add level of quoting to each line? - * @param array $opts Additional options: - *
-     * 'nowrap' - (boolean) If true, does not wrap unquoted lines.
-     *            DEFAULT: false
-     * 
- * - * @return string The text converted to RFC 2646 'flowed' format. - */ - public function toFlowed($quote = false, array $opts = array()) - { - $txt = ''; - - $this->_reformat(true, $quote, empty($opts['nowrap'])); - foreach ($this->_output as $line) { - $txt .= $line['text'] . "\n"; - } - - return $txt; - } - - /** - * Reformats the input string, where the string is 'format=flowed' plain - * text as described in RFC 2646. - * - * @param boolean $toflowed Convert to flowed? - * @param boolean $quote Add level of quoting to each line? - * @param boolean $wrap Wrap unquoted lines? - */ - protected function _reformat($toflowed, $quote, $wrap = true) - { - $format_type = implode('|', array($toflowed, $quote)); - if ($format_type == $this->_formattype) { - return; - } - - $this->_output = array(); - $this->_formattype = $format_type; - - /* Set variables used in regexps. */ - $delsp = ($toflowed && $this->_delsp) ? 1 : 0; - $opt = $this->_optlength - 1 - $delsp; - - /* Process message line by line. */ - $text = preg_split("/\r?\n/", $this->_text); - $text_count = count($text) - 1; - $skip = 0; - - foreach ($text as $no => $line) { - if ($skip) { - --$skip; - continue; - } - - /* Per RFC 2646 [4.3], the 'Usenet Signature Convention' line - * (DASH DASH SP) is not considered flowed. Watch for this when - * dealing with potentially flowed lines. */ - - /* The next three steps come from RFC 2646 [4.2]. */ - /* STEP 1: Determine quote level for line. */ - if (($num_quotes = $this->_numquotes($line))) { - $line = substr($line, $num_quotes); - } - - /* Only combine lines if we are converting to flowed or if the - * current line is quoted. */ - if (!$toflowed || $num_quotes) { - /* STEP 2: Remove space stuffing from line. */ - $line = $this->_unstuff($line); - - /* STEP 3: Should we interpret this line as flowed? - * While line is flowed (not empty and there is a space - * at the end of the line), and there is a next line, and the - * next line has the same quote depth, add to the current - * line. A line is not flowed if it is a signature line. */ - if ($line != '-- ') { - while (!empty($line) && - (substr($line, -1) == ' ') && - ($text_count != $no) && - ($this->_numquotes($text[$no + 1]) == $num_quotes)) { - /* If DelSp is yes and this is flowed input, we need to - * remove the trailing space. */ - if (!$toflowed && $this->_delsp) { - $line = substr($line, 0, -1); - } - $line .= $this->_unstuff(substr($text[++$no], $num_quotes)); - ++$skip; - } - } - } - - /* Ensure line is fixed, since we already joined all flowed - * lines. Remove all trailing ' ' from the line. */ - if ($line != '-- ') { - $line = rtrim($line); - } - - /* Increment quote depth if we're quoting. */ - if ($quote) { - $num_quotes++; - } - - /* The quote prefix for the line. */ - $quotestr = str_repeat('>', $num_quotes); - - if (empty($line)) { - /* Line is empty. */ - $this->_output[] = array('text' => $quotestr, 'level' => $num_quotes); - } elseif ((!$wrap && !$num_quotes) || - empty($this->_maxlength) || - ((Horde_String::length($line, $this->_charset) + $num_quotes) <= $this->_maxlength)) { - /* Line does not require rewrapping. */ - $this->_output[] = array('text' => $quotestr . $this->_stuff($line, $num_quotes, $toflowed), 'level' => $num_quotes); - } else { - $min = $num_quotes + 1; - - /* Rewrap this paragraph. */ - while ($line) { - /* Stuff and re-quote the line. */ - $line = $quotestr . $this->_stuff($line, $num_quotes, $toflowed); - $line_length = Horde_String::length($line, $this->_charset); - if ($line_length <= $this->_optlength) { - /* Remaining section of line is short enough. */ - $this->_output[] = array('text' => $line, 'level' => $num_quotes); - break; - } else { - $regex = array(); - if ($min <= $opt) { - $regex[] = '^(.{' . $min . ',' . $opt . '}) (.*)'; - } - if ($min <= $this->_maxlength) { - $regex[] = '^(.{' . $min . ',' . $this->_maxlength . '}) (.*)'; - } - $regex[] = '^(.{' . $min . ',})? (.*)'; - - if ($m = Horde_String::regexMatch($line, $regex, $this->_charset)) { - /* We need to wrap text at a certain number of - * *characters*, not a certain number of *bytes*; - * thus the need for a multibyte capable regex. - * If a multibyte regex isn't available, we are - * stuck with preg_match() (the function will - * still work - are just left with shorter rows - * than expected if multibyte characters exist in - * the row). - * - * 1. Try to find a string as long as _optlength. - * 2. Try to find a string as long as _maxlength. - * 3. Take the first word. */ - if (empty($m[1])) { - $m[1] = $m[2]; - $m[2] = ''; - } - $this->_output[] = array('text' => $m[1] . ' ' . (($delsp) ? ' ' : ''), 'level' => $num_quotes); - $line = $m[2]; - } elseif ($line_length > 998) { - /* One excessively long word left on line. Be - * absolutely sure it does not exceed 998 - * characters in length or else we must - * truncate. */ - $this->_output[] = array('text' => Horde_String::substr($line, 0, 998, $this->_charset), 'level' => $num_quotes); - $line = Horde_String::substr($line, 998, null, $this->_charset); - } else { - $this->_output[] = array('text' => $line, 'level' => $num_quotes); - break; - } - } - } - } - } - } - - /** - * Returns the number of leading '>' characters in the text input. - * '>' characters are defined by RFC 2646 to indicate a quoted line. - * - * @param string $text The text to analyze. - * - * @return integer The number of leading quote characters. - */ - protected function _numquotes($text) - { - return strspn($text, '>'); - } - - /** - * Space-stuffs if it starts with ' ' or '>' or 'From ', or if - * quote depth is non-zero (for aesthetic reasons so that there is a - * space after the '>'). - * - * @param string $text The text to stuff. - * @param string $num_quotes The quote-level of this line. - * @param boolean $toflowed Are we converting to flowed text? - * - * @return string The stuffed text. - */ - protected function _stuff($text, $num_quotes, $toflowed) - { - return ($toflowed && ($num_quotes || preg_match("/^(?: |>|From |From$)/", $text))) - ? ' ' . $text - : $text; - } - - /** - * Unstuffs a space stuffed line. - * - * @param string $text The text to unstuff. - * - * @return string The unstuffed text. - */ - protected function _unstuff($text) - { - return (!empty($text) && ($text[0] == ' ')) - ? substr($text, 1) - : $text; - } - -} diff --git a/lib/horde/framework/Horde/Translation.php b/lib/horde/framework/Horde/Translation.php deleted file mode 100644 index 1dff41a7919..00000000000 --- a/lib/horde/framework/Horde/Translation.php +++ /dev/null @@ -1,132 +0,0 @@ - - * @category Horde - * @copyright 2010-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Translation - */ -abstract class Horde_Translation -{ - /** - * The translation domain, e.g. the library name, for the default gettext - * handler. - * - * @var string - */ - protected static $_domain; - - /** - * The relative path to the translations for the default gettext handler. - * - * @var string - */ - protected static $_directory; - - /** - * The handlers providing the actual translations. - * - * @var array - */ - protected static $_handlers = array(); - - /** - * Loads a translation handler class pointing to the library's translations - * and assigns it to $_handler. - * - * @param string $handlerClass The name of a class implementing the - * Horde_Translation_Handler interface. - */ - public static function loadHandler($handlerClass) - { - if (!static::$_domain || !static::$_directory) { - throw new Horde_Translation_Exception('The domain and directory properties must be set by the class that extends Horde_Translation.'); - } - static::setHandler(static::$_domain, new $handlerClass(static::$_domain, static::$_directory)); - } - - /** - * Assigns a translation handler object to $_handlers. - * - * Type hinting isn't used on purpose. You should extend a custom - * translation handler passed here from the Horde_Translation interface, - * but technically it's sufficient if you provide the API of that - * interface. - * - * @param string $domain The translation domain. - * @param Horde_Translation_Handler $handler An object implementing the - * Horde_Translation_Handler - * interface. - */ - public static function setHandler($domain, $handler) - { - static::$_handlers[$domain] = $handler; - } - - /** - * Returns the translation of a message. - * - * @var string $message The string to translate. - * - * @return string The string translation, or the original string if no - * translation exists. - */ - public static function t($message) - { - if (!isset(static::$_handlers[static::$_domain])) { - static::loadHandler('Horde_Translation_Handler_Gettext'); - } - return static::$_handlers[static::$_domain]->t($message); - } - - /** - * Returns the plural translation of a message. - * - * @param string $singular The singular version to translate. - * @param string $plural The plural version to translate. - * @param integer $number The number that determines singular vs. plural. - * - * @return string The string translation, or the original string if no - * translation exists. - */ - public static function ngettext($singular, $plural, $number) - { - if (!isset(static::$_handlers[static::$_domain])) { - static::loadHandler('Horde_Translation_Handler_Gettext'); - } - return static::$_handlers[static::$_domain]->ngettext($singular, $plural, $number); - } - - /** - * Allows a gettext string to be defined and recognized as a string by - * the horde translation utilities, but no translation is actually - * performed (raw gettext = r()). - * - * @since 2.1.0 - * - * @param string $message The raw string to mark for translation. - * - * @return string The raw string. - */ - public static function r($message) - { - return $message; - } - -} diff --git a/lib/horde/framework/Horde/Translation/Autodetect.php b/lib/horde/framework/Horde/Translation/Autodetect.php deleted file mode 100644 index 5d59e87918b..00000000000 --- a/lib/horde/framework/Horde/Translation/Autodetect.php +++ /dev/null @@ -1,103 +0,0 @@ - - * @category Horde - * @copyright 2010-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Translation - * @since 2.2.0 - */ -abstract class Horde_Translation_Autodetect extends Horde_Translation -{ - /** - * The absolute PEAR path to the translations for the default gettext handler. - * - * This value is automatically set by PEAR Replace Tasks. - * - * @var string - */ - protected static $_pearDirectory; - - /** - * Auto detects the locale directory location. - * - * @param string $handlerClass The name of a class implementing the - * Horde_Translation_Handler interface. - */ - public static function loadHandler($handlerClass) - { - if (!static::$_domain) { - throw new Horde_Translation_Exception('The domain property must be set by the class that extends Horde_Translation_Autodetect.'); - } - - $directory = static::_searchLocaleDirectory(); - if (!$directory) { - throw new Horde_Translation_Exception(sprintf('Could not found find any locale directory for %s domain.', static::$_domain)); - } - - static::$_directory = $directory; - parent::loadHandler($handlerClass); - } - - /** - * Search for the locale directory for different installations methods (eg: PEAR, Composer). - * - * @var boolean|string The directory if found, or false when no valid directory is found - */ - protected static function _searchLocaleDirectory() - { - if (static::$_pearDirectory !== '@data_dir@') { - $directory = static::$_pearDirectory . '/' . static::$_domain . '/locale'; - if (is_dir($directory)) { - return $directory; - } - } - - $directories = static::_getSearchDirectories(); - foreach ($directories as $directory) { - if (is_dir($directory)) { - return $directory; - } - } - - return false; - } - - /** - * Get potential locations for the locale directory. - * - * @var array List of directories - */ - protected static function _getSearchDirectories() - { - $className = get_called_class(); - $class = new ReflectionClass($className); - $basedir = dirname($class->getFilename()); - $depth = substr_count($className, '\\') - ?: substr_count($className, '_'); - - return array( - /* Composer */ - $basedir . str_repeat('/..', $depth) . '/data/locale', - /* Source */ - $basedir . str_repeat('/..', $depth + 1) . '/locale' - ); - } - -} diff --git a/lib/horde/framework/Horde/Translation/Exception.php b/lib/horde/framework/Horde/Translation/Exception.php deleted file mode 100644 index e265d6ea94b..00000000000 --- a/lib/horde/framework/Horde/Translation/Exception.php +++ /dev/null @@ -1,15 +0,0 @@ - - * @package Translation - */ -class Horde_Translation_Exception extends Exception -{ -} diff --git a/lib/horde/framework/Horde/Translation/Handler.php b/lib/horde/framework/Horde/Translation/Handler.php deleted file mode 100644 index 69a40a4cda0..00000000000 --- a/lib/horde/framework/Horde/Translation/Handler.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @package Translation - */ -interface Horde_Translation_Handler -{ - /** - * Returns the translation of a message. - * - * @var string $message The string to translate. - * - * @return string The string translation, or the original string if no - * translation exists. - */ - public function t($message); - - /** - * Returns the plural translation of a message. - * - * @param string $singular The singular version to translate. - * @param string $plural The plural version to translate. - * @param integer $number The number that determines singular vs. plural. - * - * @return string The string translation, or the original string if no - * translation exists. - */ - public function ngettext($singular, $plural, $number); -} diff --git a/lib/horde/framework/Horde/Translation/Handler/Gettext.php b/lib/horde/framework/Horde/Translation/Handler/Gettext.php deleted file mode 100644 index f08365f5cb5..00000000000 --- a/lib/horde/framework/Horde/Translation/Handler/Gettext.php +++ /dev/null @@ -1,82 +0,0 @@ - - * @package Translation - */ -class Horde_Translation_Handler_Gettext implements Horde_Translation_Handler -{ - /** - * The translation domain, e.g. package name. - * - * @var string - */ - protected $_domain; - - /** - * Whether the gettext extension is installed. - * - * @var boolean - */ - protected $_gettext; - - /** - * Constructor. - * - * @param string $domain The translation domain, e.g. package name. - * @param string $path The path to the gettext catalog. - */ - public function __construct($domain, $path) - { - if (!is_dir($path)) { - throw new InvalidArgumentException("$path is not a directory"); - } - $this->_gettext = function_exists('_'); - if (!$this->_gettext) { - return; - } - $this->_domain = $domain; - bindtextdomain($this->_domain, $path); - } - - /** - * Returns the translation of a message. - * - * @param string $message The string to translate. - * - * @return string The string translation, or the original string if no - * translation exists. - */ - public function t($message) - { - return $this->_gettext ? dgettext($this->_domain, $message) : $message; - } - - /** - * Returns the plural translation of a message. - * - * @param string $singular The singular version to translate. - * @param string $plural The plural version to translate. - * @param integer $number The number that determines singular vs. plural. - * - * @return string The string translation, or the original string if no - * translation exists. - */ - public function ngettext($singular, $plural, $number) - { - return $this->_gettext - ? dngettext($this->_domain, $singular, $plural, $number) - : ($number > 1 ? $plural : $singular); - } -} diff --git a/lib/horde/framework/Horde/Util.php b/lib/horde/framework/Horde/Util.php deleted file mode 100644 index d6d111d47be..00000000000 --- a/lib/horde/framework/Horde/Util.php +++ /dev/null @@ -1,577 +0,0 @@ - - * @author Jon Parise - * @category Horde - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Util - */ -class Horde_Util -{ - /** - * A list of random patterns to use for overwriting purposes. - * See http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html. - * We save the random overwrites for efficiency reasons. - * - * @var array - */ - public static $patterns = array( - "\x55", "\xaa", "\x92\x49\x24", "\x49\x24\x92", "\x24\x92\x49", - "\x00", "\x11", "\x22", "\x33", "\x44", "\x55", "\x66", "\x77", - "\x88", "\x99", "\xaa", "\xbb", "\xcc", "\xdd", "\xee", "\xff", - "\x92\x49\x24", "\x49\x24\x92", "\x24\x92\x49", "\x6d\xb6\xdb", - "\xb6\xdb\x6d", "\xdb\x6d\xb6" - ); - - /** - * Are magic quotes in use? - * - * @var boolean - */ - protected static $_magicquotes = null; - - /** - * Data used to determine shutdown deletion. - * - * @var array - */ - protected static $_shutdowndata = array( - 'paths' => array(), - 'secure' => array() - ); - - /** - * Has the shutdown method been registered? - * - * @var boolean - */ - protected static $_shutdownreg = false; - - /** - * Cache for extensionExists(). - * - * @var array - */ - protected static $_cache = array(); - - /** - * Checks to see if a value has been set by the script and not by GET, - * POST, or cookie input. The value being checked MUST be in the global - * scope. - * - * @param string $varname The variable name to check. - * @param mixed $default Default value if the variable isn't present - * or was specified by the user. Defaults to null. - * - * @return mixed $default if the var is in user input or not present, - * the variable value otherwise. - */ - public static function nonInputVar($varname, $default = null) - { - return (isset($_GET[$varname]) || isset($_POST[$varname]) || isset($_COOKIE[$varname])) - ? $default - : (isset($GLOBALS[$varname]) ? $GLOBALS[$varname] : $default); - } - - /** - * Returns a hidden form input containing the session name and id. - * - * @param boolean $append_session 0 = only if needed, 1 = always. - * - * @return string The hidden form input, if needed/requested. - */ - public static function formInput($append_session = 0) - { - return (($append_session == 1) || !isset($_COOKIE[session_name()])) - ? '\n" - : ''; - } - - /** - * Prints a hidden form input containing the session name and id. - * - * @param boolean $append_session 0 = only if needed, 1 = always. - */ - public static function pformInput($append_session = 0) - { - echo self::formInput($append_session); - } - - /** - * If magic_quotes_gpc is in use, run stripslashes() on $var. - * - * @param mixed $var The string, or an array of strings, to un-quote. - * - * @return mixed $var, minus any magic quotes. - */ - public static function dispelMagicQuotes($var) - { - if (is_null(self::$_magicquotes)) { - self::$_magicquotes = function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc(); - } - - if (self::$_magicquotes) { - $var = is_array($var) - ? array_map(array(__CLASS__, 'dispelMagicQuotes'), $var) - : stripslashes($var); - } - - return $var; - } - - /** - * Gets a form variable from GET or POST data, stripped of magic quotes if - * necessary. If the variable is somehow set in both the GET data and the - * POST data, the value from the POST data will be returned and the GET - * value will be ignored. - * - * @param string $var The name of the form variable to look for. - * @param string $default The value to return if the variable is not - * there. - * - * @return string The cleaned form variable, or $default. - */ - public static function getFormData($var, $default = null) - { - return (($val = self::getPost($var)) !== null) - ? $val - : self::getGet($var, $default); - } - - /** - * Gets a form variable from GET data, stripped of magic quotes if - * necessary. This function will NOT return a POST variable. - * - * @param string $var The name of the form variable to look for. - * @param string $default The value to return if the variable is not - * there. - * - * @return string The cleaned form variable, or $default. - */ - public static function getGet($var, $default = null) - { - return (isset($_GET[$var])) - ? self::dispelMagicQuotes($_GET[$var]) - : $default; - } - - /** - * Gets a form variable from POST data, stripped of magic quotes if - * necessary. This function will NOT return a GET variable. - * - * @param string $var The name of the form variable to look for. - * @param string $default The value to return if the variable is not - * there. - * - * @return string The cleaned form variable, or $default. - */ - public static function getPost($var, $default = null) - { - return (isset($_POST[$var])) - ? self::dispelMagicQuotes($_POST[$var]) - : $default; - } - - /** - * Creates a temporary filename for the lifetime of the script, and - * (optionally) registers it to be deleted at request shutdown. - * - * @param string $prefix Prefix to make the temporary name more - * recognizable. - * @param boolean $delete Delete the file at the end of the request? - * @param string $dir Directory to create the temporary file in. - * @param boolean $secure If deleting the file, should we securely delete - * the file by overwriting it with random data? - * - * @return string Returns the full path-name to the temporary file. - * Returns false if a temp file could not be created. - */ - public static function getTempFile($prefix = '', $delete = true, $dir = '', - $secure = false) - { - $tempDir = (empty($dir) || !is_dir($dir)) - ? sys_get_temp_dir() - : $dir; - - $tempFile = tempnam($tempDir, $prefix); - - // If the file was created, then register it for deletion and return. - if (empty($tempFile)) { - return false; - } - - if ($delete) { - self::deleteAtShutdown($tempFile, true, $secure); - } - - return $tempFile; - } - - /** - * Creates a temporary filename with a specific extension for the lifetime - * of the script, and (optionally) registers it to be deleted at request - * shutdown. - * - * @param string $extension The file extension to use. - * @param string $prefix Prefix to make the temporary name more - * recognizable. - * @param boolean $delete Delete the file at the end of the request? - * @param string $dir Directory to create the temporary file in. - * @param boolean $secure If deleting file, should we securely delete - * the file by overwriting it with random data? - * - * @return string Returns the full path-name to the temporary file. - * Returns false if a temporary file could not be created. - */ - public static function getTempFileWithExtension($extension = '.tmp', - $prefix = '', - $delete = true, $dir = '', - $secure = false) - { - $tempDir = (empty($dir) || !is_dir($dir)) - ? sys_get_temp_dir() - : $dir; - - if (empty($tempDir)) { - return false; - } - - $windows = substr(PHP_OS, 0, 3) == 'WIN'; - $tries = 1; - do { - // Get a known, unique temporary file name. - $sysFileName = tempnam($tempDir, $prefix); - if ($sysFileName === false) { - return false; - } - - // tack on the extension - $tmpFileName = $sysFileName . $extension; - if ($sysFileName == $tmpFileName) { - return $sysFileName; - } - - // Move or point the created temporary file to the full filename - // with extension. These calls fail if the new name already - // exists. - $fileCreated = ($windows ? @rename($sysFileName, $tmpFileName) : @link($sysFileName, $tmpFileName)); - if ($fileCreated) { - if (!$windows) { - unlink($sysFileName); - } - - if ($delete) { - self::deleteAtShutdown($tmpFileName, true, $secure); - } - - return $tmpFileName; - } - - unlink($sysFileName); - } while (++$tries <= 5); - - return false; - } - - /** - * Creates a temporary directory in the system's temporary directory. - * - * @param boolean $delete Delete the temporary directory at the end of - * the request? - * @param string $temp_dir Use this temporary directory as the directory - * where the temporary directory will be created. - * - * @return string The pathname to the new temporary directory. - * Returns false if directory not created. - */ - public static function createTempDir($delete = true, $temp_dir = null) - { - if (is_null($temp_dir)) { - $temp_dir = sys_get_temp_dir(); - } - - if (empty($temp_dir)) { - return false; - } - - /* Get the first 8 characters of a random string to use as a temporary - directory name. */ - do { - $new_dir = $temp_dir . '/' . substr(base_convert(uniqid(mt_rand()), 16, 36), 0, 8); - } while (file_exists($new_dir)); - - $old_umask = umask(0000); - if (!mkdir($new_dir, 0700)) { - $new_dir = false; - } elseif ($delete) { - self::deleteAtShutdown($new_dir); - } - umask($old_umask); - - return $new_dir; - } - - /** - * Returns the canonical path of the string. Like PHP's built-in - * realpath() except the directory need not exist on the local server. - * - * Algorithim loosely based on code from the Perl File::Spec::Unix module - * (version 1.5). - * - * @param string $path A file path. - * - * @return string The canonicalized file path. - */ - public static function realPath($path) - { - /* Standardize on UNIX directory separators. */ - if (!strncasecmp(PHP_OS, 'WIN', 3)) { - $path = str_replace('\\', '/', $path); - } - - /* xx////xx -> xx/xx - * xx/././xx -> xx/xx */ - $path = preg_replace(array("|/+|", "@(/\.)+(/|\Z(?!\n))@"), array('/', '/'), $path); - - /* ./xx -> xx */ - if ($path != './') { - $path = preg_replace("|^(\./)+|", '', $path); - } - - /* /../../xx -> xx */ - $path = preg_replace("|^/(\.\./?)+|", '/', $path); - - /* xx/ -> xx */ - if ($path != '/') { - $path = preg_replace("|/\Z(?!\n)|", '', $path); - } - - /* /xx/.. -> / */ - while (strpos($path, '/..') !== false) { - $path = preg_replace("|/[^/]+/\.\.|", '', $path); - } - - return empty($path) ? '/' : $path; - } - - /** - * Removes given elements at request shutdown. - * - * If called with a filename will delete that file at request shutdown; if - * called with a directory will remove that directory and all files in that - * directory at request shutdown. - * - * If called with no arguments, return all elements to be deleted (this - * should only be done by Horde_Util::_deleteAtShutdown()). - * - * The first time it is called, it initializes the array and registers - * Horde_Util::_deleteAtShutdown() as a shutdown function - no need to do - * so manually. - * - * The second parameter allows the unregistering of previously registered - * elements. - * - * @param string $filename The filename to be deleted at the end of the - * request. - * @param boolean $register If true, then register the element for - * deletion, otherwise, unregister it. - * @param boolean $secure If deleting file, should we securely delete - * the file? - */ - public static function deleteAtShutdown($filename, $register = true, - $secure = false) - { - /* Initialization of variables and shutdown functions. */ - if (!self::$_shutdownreg) { - register_shutdown_function(array(__CLASS__, 'shutdown')); - self::$_shutdownreg = true; - } - - $ptr = &self::$_shutdowndata; - if ($register) { - $ptr['paths'][$filename] = true; - if ($secure) { - $ptr['secure'][$filename] = true; - } - } else { - unset($ptr['paths'][$filename], $ptr['secure'][$filename]); - } - } - - /** - * Deletes registered files at request shutdown. - * - * This function should never be called manually; it is registered as a - * shutdown function by Horde_Util::deleteAtShutdown() and called - * automatically at the end of the request. - * - * Contains code from gpg_functions.php. - * Copyright 2002-2003 Braverock Ventures - */ - public static function shutdown() - { - $ptr = &self::$_shutdowndata; - - foreach (array_keys($ptr['paths']) as $val) { - if (@is_file($val)) { - self::_secureDelete($val); - continue; - } - - try { - $it = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($val), - RecursiveIteratorIterator::CHILD_FIRST - ); - } catch (UnexpectedValueException $e) { - continue; - } - - while ($it->valid()) { - if (!$it->isDot()) { - if ($it->isDir()) { - @rmdir($it->key()); - } elseif ($it->isFile()) { - self::_secureDelete($it->key()); - } else { - @unlink($it->key()); - } - } - $it->next(); - } - - @rmdir($val); - } - } - - /** - * Securely delete the file by overwriting the data with a random - * string. - * - * @param string $file Filename. - */ - protected static function _secureDelete($file) - { - if (isset($ptr['secure'][$file])) { - $filesize = filesize($file); - $fp = fopen($file, 'r+'); - foreach (self::$patterns as $pattern) { - $pattern = substr(str_repeat($pattern, floor($filesize / strlen($pattern)) + 1), 0, $filesize); - fwrite($fp, $pattern); - fseek($fp, 0); - } - fclose($fp); - } - - @unlink($file); - } - - /** - * Caches the result of extension_loaded() calls. - * - * @param string $ext The extension name. - * - * @return boolean Is the extension loaded? - */ - public static function extensionExists($ext) - { - if (!isset(self::$_cache[$ext])) { - self::$_cache[$ext] = extension_loaded($ext); - } - - return self::$_cache[$ext]; - } - - /** - * Tries to load a PHP extension, behaving correctly for all operating - * systems. - * - * @param string $ext The extension to load. - * - * @return boolean True if the extension is now loaded, false if not. - * True can mean that the extension was already loaded, - * OR was loaded dynamically. - */ - public static function loadExtension($ext) - { - /* If $ext is already loaded, our work is done. */ - if (self::extensionExists($ext)) { - return true; - } - - /* See if we can call dl() at all, by the current ini settings. - * dl() has been removed in some PHP 5.3 SAPIs. */ - if ((ini_get('enable_dl') != 1) || - (ini_get('safe_mode') == 1) || - !function_exists('dl')) { - return false; - } - - if (!strncasecmp(PHP_OS, 'WIN', 3)) { - $suffix = 'dll'; - } else { - switch (PHP_OS) { - case 'HP-UX': - $suffix = 'sl'; - break; - - case 'AIX': - $suffix = 'a'; - break; - - case 'OSX': - $suffix = 'bundle'; - break; - - default: - $suffix = 'so'; - } - } - - return dl($ext . '.' . $suffix) || dl('php_' . $ext . '.' . $suffix); - } - - /** - * Utility function to obtain PATH_INFO information. - * - * @return string The PATH_INFO string. - */ - public static function getPathInfo() - { - if (isset($_SERVER['PATH_INFO']) && - (strpos($_SERVER['SERVER_SOFTWARE'], 'lighttpd') === false)) { - return $_SERVER['PATH_INFO']; - } elseif (isset($_SERVER['REQUEST_URI']) && - isset($_SERVER['SCRIPT_NAME'])) { - $search = Horde_String::common($_SERVER['SCRIPT_NAME'], $_SERVER['REQUEST_URI']); - if (substr($search, -1) == '/') { - $search = substr($search, 0, -1); - } - $search = array($search); - if (!empty($_SERVER['QUERY_STRING'])) { - // We can't use QUERY_STRING directly because URL rewriting - // might add more parameters to the query string than those - // from the request URI. - $url = parse_url($_SERVER['REQUEST_URI']); - if (!empty($url['query'])) { - $search[] = '?' . $url['query']; - } - } - $path = str_replace($search, '', $_SERVER['REQUEST_URI']); - if ($path == '/') { - $path = ''; - } - return $path; - } - - return ''; - } - -} diff --git a/lib/horde/framework/Horde/Variables.php b/lib/horde/framework/Horde/Variables.php deleted file mode 100644 index ffb3782fd90..00000000000 --- a/lib/horde/framework/Horde/Variables.php +++ /dev/null @@ -1,403 +0,0 @@ - - * @author Chuck Hagenbuch - * @author Michael Slusarz - * @category Horde - * @copyright 2009-2017 Horde LLC - * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 - * @package Util - */ -class Horde_Variables implements ArrayAccess, Countable, IteratorAggregate -{ - /** - * The list of expected variables. - * - * @var array - */ - protected $_expected = array(); - - /** - * Has the input been sanitized? - * - * @var boolean - */ - protected $_sanitized = false; - - /** - * Array of form variables. - * - * @var array - */ - protected $_vars; - - /** - * Returns a Horde_Variables object populated with the form input. - * - * @param string $sanitize Sanitize the input variables? - * - * @return Horde_Variables Variables object. - */ - public static function getDefaultVariables($sanitize = false) - { - return new self(null, $sanitize); - } - - /** - * Constructor. - * - * @param array $vars The list of form variables (if null, defaults - * to PHP's $_REQUEST value). If '_formvars' - * exists, it must be a JSON encoded array that - * contains the list of allowed form variables. - * @param string $sanitize Sanitize the input variables? - */ - public function __construct($vars = array(), $sanitize = false) - { - if (is_null($vars)) { - $request_copy = $_REQUEST; - $vars = Horde_Util::dispelMagicQuotes($request_copy); - } - - if (isset($vars['_formvars'])) { - $this->_expected = @json_decode($vars['_formvars'], true); - unset($vars['_formvars']); - } - - $this->_vars = $vars; - - if ($sanitize) { - $this->sanitize(); - } - } - - /** - * Sanitize the form input. - */ - public function sanitize() - { - if (!$this->_sanitized) { - foreach (array_keys($this->_vars) as $key) { - $this->$key = $this->filter($key); - } - $this->_sanitized = true; - } - } - - /** - * Alias of isset(). - * - * @see __isset() - */ - public function exists($varname) - { - return $this->__isset($varname); - } - - /** - * isset() implementation. - * - * @param string $varname The form variable name. - * - * @return boolean Does $varname form variable exist? - */ - public function __isset($varname) - { - return count($this->_expected) - ? $this->_getExists($this->_expected, $varname, $value) - : $this->_getExists($this->_vars, $varname, $value); - } - - /** - * Implements isset() for ArrayAccess interface. - * - * @see __isset() - */ - public function offsetExists($field) - { - return $this->__isset($field); - } - - /** - * Returns the value of a given form variable. - * - * @param string $varname The form variable name. - * @param string $default The default form variable value. - * - * @return mixed The form variable, or $default if it doesn't exist. - */ - public function get($varname, $default = null) - { - return $this->_getExists($this->_vars, $varname, $value) - ? $value - : $default; - } - - /** - * Returns the value of a given form variable. - * - * @param string $varname The form variable name. - * - * @return mixed The form variable, or null if it doesn't exist. - */ - public function __get($varname) - { - $this->_getExists($this->_vars, $varname, $value); - return $value; - } - - /** - * Implements getter for ArrayAccess interface. - * - * @see __get() - */ - public function offsetGet($field) - { - return $this->__get($field); - } - - /** - * Given a variable name, returns the value and sets a variable indicating - * whether the value exists in the form data. - * - * @param string $varname The form variable name. - * @param boolean &$exists Reference to variable that will indicate - * whether $varname existed in form data. - * - * @return mixed The form variable, or null if it doesn't exist. - */ - public function getExists($varname, &$exists) - { - $exists = $this->_getExists($this->_vars, $varname, $value); - return $value; - } - - /** - * Sets the value of a given form variable. - * - * @see __set() - */ - public function set($varname, $value) - { - $this->$varname = $value; - } - - /** - * Sets the value of a given form variable. - * - * @param string $varname The form variable name. - * @param mixed $value The value to set. - */ - public function __set($varname, $value) - { - $keys = array(); - - if (Horde_Array::getArrayParts($varname, $base, $keys)) { - array_unshift($keys, $base); - $place = &$this->_vars; - $i = count($keys); - - while ($i--) { - $key = array_shift($keys); - if (!isset($place[$key])) { - $place[$key] = array(); - } - $place = &$place[$key]; - } - - $place = $value; - } else { - $this->_vars[$varname] = $value; - } - } - - /** - * Implements setter for ArrayAccess interface. - * - * @see __set() - */ - public function offsetSet($field, $value) - { - $this->__set($field, $value); - } - - /** - * Deletes a given form variable. - * - * @see __unset() - */ - public function remove($varname) - { - unset($this->$varname); - } - - /** - * Deletes a given form variable. - * - * @param string $varname The form variable name. - */ - public function __unset($varname) - { - Horde_Array::getArrayParts($varname, $base, $keys); - - if (is_null($base)) { - unset($this->_vars[$varname]); - } else { - $ptr = &$this->_vars[$base]; - $end = count($keys) - 1; - foreach ($keys as $key => $val) { - if (!isset($ptr[$val])) { - break; - } - if ($end == $key) { - array_splice($ptr, array_search($val, array_keys($ptr)), 1); - } else { - $ptr = &$ptr[$val]; - } - } - } - } - - /** - * Implements unset() for ArrayAccess interface. - * - * @see __unset() - */ - public function offsetUnset($field) - { - $this->__unset($field); - } - - /** - * Merges a list of variables into the current form variable list. - * - * @param array $vars Form variables. - */ - public function merge($vars) - { - foreach ($vars as $varname => $value) { - $this->$varname = $value; - } - } - - /** - * Set $varname to $value ONLY if it's not already present. - * - * @param string $varname The form variable name. - * @param mixed $value The value to set. - * - * @return boolean True if the value was altered. - */ - public function add($varname, $value) - { - if ($this->exists($varname)) { - return false; - } - - $this->_vars[$varname] = $value; - return true; - } - - /** - * Filters a form value so that it can be used in HTML output. - * - * @param string $varname The form variable name. - * - * @return mixed The filtered variable, or null if it doesn't exist. - */ - public function filter($varname) - { - $val = $this->$varname; - - if (is_null($val) || $this->_sanitized) { - return $val; - } - - return is_array($val) - ? filter_var_array($val, FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES) - : filter_var($val, FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES); - } - - /* Protected methods. */ - - /** - * Fetch the requested variable ($varname) into $value, and return - * whether or not the variable was set in $array. - * - * @param array $array The array to search in (usually either - * $this->_vars or $this->_expected). - * @param string $varname The name of the variable to look for. - * @param mixed &$value $varname's value gets assigned to this variable. - * - * @return boolean Whether or not the variable was set (or, if we've - * checked $this->_expected, should have been set). - */ - protected function _getExists($array, $varname, &$value) - { - if (Horde_Array::getArrayParts($varname, $base, $keys)) { - if (!isset($array[$base])) { - $value = null; - return false; - } - - $searchspace = &$array[$base]; - $i = count($keys); - - while ($i--) { - $key = array_shift($keys); - if (!isset($searchspace[$key])) { - $value = null; - return false; - } - $searchspace = &$searchspace[$key]; - } - $value = $searchspace; - - return true; - } - - $value = isset($array[$varname]) - ? $array[$varname] - : null; - - return !is_null($value); - } - - /* Countable methods. */ - - /** - */ - public function count() - { - return count($this->_vars); - } - - /* IteratorAggregate method. */ - - public function getIterator() - { - return new ArrayIterator($this->_vars); - } - -} diff --git a/lib/horde/locale/Horde_Exception.pot b/lib/horde/locale/Horde_Exception.pot deleted file mode 100644 index b332e5ceceb..00000000000 --- a/lib/horde/locale/Horde_Exception.pot +++ /dev/null @@ -1,26 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2017-07-26 12:13+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:37 -msgid "Not Found" -msgstr "" - -#: lib/Horde/Exception/PermissionDenied.php:37 -msgid "Permission Denied" -msgstr "" diff --git a/lib/horde/locale/Horde_Idna.pot b/lib/horde/locale/Horde_Idna.pot deleted file mode 100644 index 89a4a0264ef..00000000000 --- a/lib/horde/locale/Horde_Idna.pot +++ /dev/null @@ -1,70 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Idna package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Horde_Idna\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2017-07-26 12:13+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Idna.php:131 -msgid "ACE label does not contain a valid label string" -msgstr "" - -#: lib/Horde/Idna.php:127 -msgid "Contains a dot" -msgstr "" - -#: lib/Horde/Idna.php:119 -msgid "Contains disallowed characters" -msgstr "" - -#: lib/Horde/Idna.php:111 -msgid "Contains hyphen in the third and fourth positions" -msgstr "" - -#: lib/Horde/Idna.php:135 -msgid "Does not meet the IDNA BiDi requirements (for right-to-left characters)" -msgstr "" - -#: lib/Horde/Idna.php:139 -msgid "Does not meet the IDNA CONTEXTJ requirements" -msgstr "" - -#: lib/Horde/Idna.php:94 -msgid "Domain name is empty" -msgstr "" - -#: lib/Horde/Idna.php:99 -msgid "Domain name is too long" -msgstr "" - -#: lib/Horde/Idna.php:107 -msgid "Ends with a hyphen" -msgstr "" - -#: lib/Horde/Idna.php:123 -msgid "Starts with \"xn--\" but does not contain valid Punycode" -msgstr "" - -#: lib/Horde/Idna.php:115 -msgid "Starts with a combining mark" -msgstr "" - -#: lib/Horde/Idna.php:103 -msgid "Starts with a hyphen" -msgstr "" - -#: lib/Horde/Idna.php:143 -msgid "Unknown error" -msgstr "" diff --git a/lib/horde/locale/Horde_Imap_Client.pot b/lib/horde/locale/Horde_Imap_Client.pot deleted file mode 100644 index 9ba4bebe682..00000000000 --- a/lib/horde/locale/Horde_Imap_Client.pot +++ /dev/null @@ -1,273 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2017-07-26 12:13+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:34 -#, php-format -msgid "%s not supported on POP3 servers." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5035 -msgid "Authentication credentials have expired." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:747 lib/Horde/Imap/Client/Socket.php:5019 -#: lib/Horde/Imap/Client/Socket/Pop3.php:441 -#: lib/Horde/Imap/Client/Socket/Pop3.php:460 -#: lib/Horde/Imap/Client/Socket/Pop3.php:486 -#: lib/Horde/Imap/Client/Socket/Pop3.php:498 -msgid "Authentication failed." -msgstr "" - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:158 -#: lib/Horde/Imap/Client/Auth/Scram.php:124 -msgid "Authentication failure." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5027 -msgid "Authentication was successful, but authorization failed." -msgstr "" - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:44 -msgid "Bad tagged response." -msgstr "" - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:45 -msgid "Cannot convert search query text to new charset" -msgstr "" - -#: lib/Horde/Imap/Client/Base.php:1924 lib/Horde/Imap/Client/Base.php:1987 -msgid "Cannot expunge read-only mailbox." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4811 -msgid "Charset used in search query is not supported on the mail server." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:1240 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:358 lib/Horde/Imap/Client/Socket.php:400 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:219 -#: lib/Horde/Imap/Client/Socket/Pop3.php:233 -msgid "Could not open secure connection to the POP3 server." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4919 -msgid "Could not save message data because it is too large." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4910 -msgid "Could not save message on server." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:606 -#: lib/Horde/Imap/Client/Socket/Pop3.php:324 -msgid "Error connecting to mail server." -msgstr "" - -#: lib/Horde/Imap/Client/Utf7imap.php:128 -#: lib/Horde/Imap/Client/Utf7imap.php:156 -#: lib/Horde/Imap/Client/Utf7imap.php:163 -#: lib/Horde/Imap/Client/Utf7imap.php:225 -#: lib/Horde/Imap/Client/Utf7imap.php:245 -#: lib/Horde/Imap/Client/Utf7imap.php:252 -#: lib/Horde/Imap/Client/Utf7imap.php:263 -#: lib/Horde/Imap/Client/Utf7imap.php:272 -msgid "Error converting UTF7-IMAP string." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4467 -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:83 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:214 -#: lib/Horde/Imap/Client/Socket/Pop3.php:1382 -msgid "Error when communicating with the mail server." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4605 -msgid "IMAP Server closed the connection." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4591 -msgid "IMAP error reported by server." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4009 -#, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4102 -#, php-format -msgid "Invalid METADATA value type \"%s\"." -msgstr "" - -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:148 -msgid "Mail server closed the connection unexpectedly." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:573 -msgid "Mail server denied authentication." -msgstr "" - -#: lib/Horde/Imap/Client/Base.php:2257 lib/Horde/Imap/Client/Base.php:2536 -#: lib/Horde/Imap/Client/Base.php:2808 lib/Horde/Imap/Client/Base.php:2893 -msgid "Mailbox does not support mod-sequences." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:370 -#: lib/Horde/Imap/Client/Socket/Pop3.php:201 -msgid "No password provided." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:498 -msgid "No supported IMAP authentication method could be found." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5043 -msgid "Operation failed due to a lack of a secure connection." -msgstr "" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1448 -msgid "POP3 error reported by server." -msgstr "" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:295 -msgid "POP3 server denied authentication." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5011 -msgid "Remote server is temporarily unavailable." -msgstr "" - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:75 -msgid "Server closed the connection unexpectedly." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:388 -msgid "Server does not support TLS connections." -msgstr "" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:219 -msgid "Server does not support secure connections." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:809 -#: lib/Horde/Imap/Client/Socket/Pop3.php:508 -msgid "Server failed verification check." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:626 -msgid "Server rejected connection." -msgstr "" - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:47 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:64 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:110 -msgid "Server write error." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4964 -msgid "The comparison algorithm was not recognized by the server." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:635 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5092 -msgid "The mail server has denied the request." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5074 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4876 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4827 -#, php-format -msgid "" -"The mail server was unable to parse the contents of the mail message: %s" -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4982 -msgid "The metadata item could not be saved because it is too large." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5000 -msgid "" -"The metadata item could not be saved because the maximum number of " -"annotations has been exceeded." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:4991 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5110 -msgid "The object could not be created because it already exists." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5119 -msgid "The object could not be deleted because it does not exist." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5101 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "" - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:46 -#, php-format -msgid "The server does not support the %s extension." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5128 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5060 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:723 -#: lib/Horde/Imap/Client/Socket/Pop3.php:379 -msgid "Unexpected response from server when authenticating." -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:839 -#: lib/Horde/Imap/Client/Socket/Pop3.php:518 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "" - -#: lib/Horde/Imap/Client/Socket.php:5051 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "" diff --git a/lib/horde/locale/Horde_Mail.pot b/lib/horde/locale/Horde_Mail.pot deleted file mode 100644 index 76eabf58a76..00000000000 --- a/lib/horde/locale/Horde_Mail.pot +++ /dev/null @@ -1,27 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mail package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mail\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2014-11-12 14:05+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mail/Mbox/Parse.php:65 -msgid "Could not parse mailbox data." -msgstr "" - -#: lib/Horde/Mail/Mbox/Parse.php:98 -#, php-format -msgid "Imported mailbox contains more than enforced limit of %u messages." -msgstr "" diff --git a/lib/horde/locale/Horde_Mime.pot b/lib/horde/locale/Horde_Mime.pot deleted file mode 100644 index bfd8c292b08..00000000000 --- a/lib/horde/locale/Horde_Mime.pot +++ /dev/null @@ -1,38 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2015-01-08 11:22+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:439 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:437 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:201 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/ar/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/ar/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 71938c4918c..00000000000 Binary files a/lib/horde/locale/ar/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/ar/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/ar/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 9e0cf60a1dc..00000000000 --- a/lib/horde/locale/ar/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,25 +0,0 @@ -# Arabic translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "غير موجود" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "" diff --git a/lib/horde/locale/ar/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/ar/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index e615918c106..00000000000 Binary files a/lib/horde/locale/ar/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/ar/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/ar/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 9ae34efdf03..00000000000 --- a/lib/horde/locale/ar/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,70 +0,0 @@ -# Arabic translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "قائمة عناوين المساعدة" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/bg/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/bg/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 71938c4918c..00000000000 Binary files a/lib/horde/locale/bg/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/bg/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/bg/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 5a55ef69aa4..00000000000 --- a/lib/horde/locale/bg/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Bulgarian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "не беше намерен" - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "Права" diff --git a/lib/horde/locale/bg/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/bg/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index e615918c106..00000000000 Binary files a/lib/horde/locale/bg/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/bg/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/bg/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 3917439cc9d..00000000000 --- a/lib/horde/locale/bg/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,70 +0,0 @@ -# Bulgarian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Помощ теми" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/bs/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/bs/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 71938c4918c..00000000000 Binary files a/lib/horde/locale/bs/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/bs/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/bs/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 36eb1629ffb..00000000000 --- a/lib/horde/locale/bs/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Bosnian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "%s nije pronađen." - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "Dozvole" diff --git a/lib/horde/locale/bs/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/bs/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index e615918c106..00000000000 Binary files a/lib/horde/locale/bs/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/bs/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/bs/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index da34bfc5cd0..00000000000 --- a/lib/horde/locale/bs/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,75 +0,0 @@ -# Bosnian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Nedozvoljena slova u email adresi." - -#: lib/Horde/Mime/Headers.php:519 -#, fuzzy -msgid "List-Archive" -msgstr "Sakrij neupisane" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Pomoć" - -#: lib/Horde/Mime/Headers.php:521 -#, fuzzy -msgid "List-Id" -msgstr "Pomoć" - -#: lib/Horde/Mime/Headers.php:517 -#, fuzzy -msgid "List-Owner" -msgstr "Pomoć" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -#, fuzzy -msgid "List-Subscribe" -msgstr "Sakrij neupisane" - -#: lib/Horde/Mime/Headers.php:515 -#, fuzzy -msgid "List-Unsubscribe" -msgstr "Sakrij neupisane" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/ca/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/ca/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 92e00ad4ca5..00000000000 Binary files a/lib/horde/locale/ca/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/ca/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/ca/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 45f990161a9..00000000000 --- a/lib/horde/locale/ca/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,25 +0,0 @@ -# Catalan translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "No s'ha trobat." - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "Permis denegat" diff --git a/lib/horde/locale/ca/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/ca/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index f93713718cc..00000000000 Binary files a/lib/horde/locale/ca/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/ca/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/ca/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 1da81723def..00000000000 --- a/lib/horde/locale/ca/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,71 +0,0 @@ -# Catalan translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Notificació de recepció" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "L'adreça de destinació no és vàlida." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "List-Archive" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "List-Help" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "List-Id" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "List-Owner" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "List-Post" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "List-Subscribe" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "List-Unsubscribe" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, fuzzy, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"S'ha mostrat el missatge enviat el %s a %s amb l'assumpte \"%s\". Això no " -"garanteix que s'hagi llegit o entès el missatge." diff --git a/lib/horde/locale/cs/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/cs/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index a2d7d9f6aed..00000000000 Binary files a/lib/horde/locale/cs/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/cs/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/cs/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index f6163685d1c..00000000000 --- a/lib/horde/locale/cs/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Czech translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "Nenalezeno." - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "Přístup odepřen" diff --git a/lib/horde/locale/cs/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/cs/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 4e22624fee8..00000000000 Binary files a/lib/horde/locale/cs/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/cs/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/cs/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 8bf14762b4c..00000000000 --- a/lib/horde/locale/cs/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,72 +0,0 @@ -# Czech translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Dispoziční upozornění" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Neplatná adresa příjemce." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "Seznam-Archiv" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "Seznam-Nápověda" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "Seznam-Id" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "Seznam-Vlastník" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "Seznam-Odeslání" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "Seznam-Přihlášení" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "Seznam-Odhlášení" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, fuzzy, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Zpráva zaslaná v %s k %s s předmětem \"%s\" byla zobrazena.\n" -"Toto nezaručuje, že zpráva byla přečtena nebo že jí adresát(ka) rozuměl(a)." diff --git a/lib/horde/locale/da/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/da/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 2c7c20999be..00000000000 Binary files a/lib/horde/locale/da/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/da/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/da/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 5c6c14e294b..00000000000 --- a/lib/horde/locale/da/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Danish translations for Horde_Exception package. -# Copyright (C) 2014 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception package. -# Erling Preben Hansen , 2013-2014. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-01-17 12:38+0100\n" -"PO-Revision-Date: 2014-03-19 21:04+0100\n" -"Last-Translator: Erling Preben Hansen \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: da\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Ikke fundet" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Tilladelse nægtet" diff --git a/lib/horde/locale/da/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/da/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index 76322ef14c5..00000000000 Binary files a/lib/horde/locale/da/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/da/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/da/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index 376b20657e3..00000000000 --- a/lib/horde/locale/da/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,266 +0,0 @@ -# Danish translations for Horde_Imap_Client package. -# Copyright (C) 2014 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# FIRST AUTHOR , 2014. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2014-03-20 00:26+0100\n" -"PO-Revision-Date: 2014-03-20 20:08+0100\n" -"Last-Translator: Erling Preben Hansen \n" -"Language-Team: \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:34 -#, php-format -msgid "%s not supported on POP3 servers." -msgstr "%s er ikke understøttet på pop3 servere" - -#: lib/Horde/Imap/Client/Socket.php:4635 -msgid "Authentication credentials have expired." -msgstr "Godkendelses rettighederne er udløbet." - -#: lib/Horde/Imap/Client/Socket.php:4619 -msgid "Authentication failed." -msgstr "Godkendelsen fejlede." - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:158 -msgid "Authentication failure." -msgstr "Godkendelses fejl." - -#: lib/Horde/Imap/Client/Socket.php:4627 -msgid "Authentication was successful, but authorization failed." -msgstr "Godkendelsen lykkedes, men autorisationen fejlede." - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:44 -msgid "Bad tagged response." -msgstr "Forkert mærket svar." - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:45 -msgid "Cannot convert search query text to new charset" -msgstr "Kan ikke konvertere søgeteksten til det nye tegnsæt" - -#: lib/Horde/Imap/Client/Base.php:2032 lib/Horde/Imap/Client/Base.php:2095 -msgid "Cannot expunge read-only mailbox." -msgstr "Kan ikke rense en Læs kun mail mappe." - -#: lib/Horde/Imap/Client/Socket.php:4413 -msgid "Charset used in search query is not supported on the mail server." -msgstr "Tegnsættet brugt i søgeteksten er ikke understøttet på mail serveren." - -#: lib/Horde/Imap/Client/Socket.php:1077 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "Kunne ikke åbne mail mappen \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:393 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "Kunne ikke åbne en sikker TLS forbindelse til IMAP serveren." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:194 -#: lib/Horde/Imap/Client/Socket/Pop3.php:208 -msgid "Could not open secure connection to the POP3 server." -msgstr "Kunne ikke åbne en sikker forbindelse til POP3 serveren." - -#: lib/Horde/Imap/Client/Socket.php:4519 -msgid "Could not save message data because it is too large." -msgstr "Kunne ikke gemme besked data da den er for stor." - -#: lib/Horde/Imap/Client/Socket.php:4510 -msgid "Could not save message on server." -msgstr "Kunne ikke gemme beskeden på serveren." - -#: lib/Horde/Imap/Client/Socket.php:574 -#: lib/Horde/Imap/Client/Socket/Pop3.php:284 -msgid "Error connecting to mail server." -msgstr "Der optod en fejl under forbindelsen til serveren." - -#: lib/Horde/Imap/Client/Utf7imap.php:128 -#: lib/Horde/Imap/Client/Utf7imap.php:156 -#: lib/Horde/Imap/Client/Utf7imap.php:163 -#: lib/Horde/Imap/Client/Utf7imap.php:225 -#: lib/Horde/Imap/Client/Utf7imap.php:245 -#: lib/Horde/Imap/Client/Utf7imap.php:252 -#: lib/Horde/Imap/Client/Utf7imap.php:263 -#: lib/Horde/Imap/Client/Utf7imap.php:272 -msgid "Error converting UTF7-IMAP string." -msgstr "Der opstod en fejl under konverteringen af UTF7 strengen." - -#: lib/Horde/Imap/Client/Socket.php:4081 -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:71 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:180 -#: lib/Horde/Imap/Client/Socket/Pop3.php:1191 -msgid "Error when communicating with the mail server." -msgstr "Der opstod en fejl under kommunikationen med mail serveren" - -#: lib/Horde/Imap/Client/Socket.php:4200 -msgid "IMAP Server closed the connection." -msgstr "IMAP serveren lukkede forbindelsen." - -#: lib/Horde/Imap/Client/Socket.php:4186 -msgid "IMAP error reported by server." -msgstr "IMAP Fejl rapporterede serveren." - -#: lib/Horde/Imap/Client/Socket.php:3682 -#, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "Ugyldig METADATA : \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:3768 -#, php-format -msgid "Invalid METADATA value type \"%s\"." -msgstr "Ugyldig METADATA værdi type \"%s\"." - -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:121 -msgid "Mail server closed the connection unexpectedly." -msgstr "Mail serveren lukkede forbindelsen uventet." - -#: lib/Horde/Imap/Client/Socket.php:542 -msgid "Mail server denied authentication." -msgstr "Mail serveren afviste godkendelse" - -#: lib/Horde/Imap/Client/Base.php:2365 lib/Horde/Imap/Client/Base.php:2685 -#: lib/Horde/Imap/Client/Base.php:2950 lib/Horde/Imap/Client/Base.php:3035 -msgid "Mailbox does not support mod-sequences." -msgstr "Mailmappen understøtter ikke mod-sequences." - -#: lib/Horde/Imap/Client/Socket.php:469 -msgid "No supported IMAP authentication method could be found." -msgstr "Der kunne ikke findes nogen IMAP godkendelses metoder." - -#: lib/Horde/Imap/Client/Socket.php:4643 -msgid "Operation failed due to a lack of a secure connection." -msgstr "Handlingen fejlede på grund af manglende sikre forbindelser." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1250 -msgid "POP3 error reported by server." -msgstr "POP3 fejl rapporteret af serveren." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:253 -msgid "POP3 server denied authentication." -msgstr "POP3 serveren afviste godkendelsen." - -#: lib/Horde/Imap/Client/Socket.php:4611 -msgid "Remote server is temporarily unavailable." -msgstr "Fjernserveren er midlertidigt ikke til rådighed." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:63 -msgid "Server closed the connection unexpectedly." -msgstr "Serveren lukkede forbindelsen uventet." - -#: lib/Horde/Imap/Client/Socket.php:381 -msgid "Server does not support TLS connections." -msgstr "Serveren understøtter ikke TLS forbindelser." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:194 -msgid "Server does not support secure connections." -msgstr "Serveren understøtter ikke sikker forbindelse." - -#: lib/Horde/Imap/Client/Socket.php:594 -msgid "Server rejected connection." -msgstr "Serveren afviste forbindelsen." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:42 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:54 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:87 -msgid "Server write error." -msgstr "Server skrive fejl." - -#: lib/Horde/Imap/Client/Socket.php:4564 -msgid "The comparison algorithm was not recognized by the server." -msgstr "DEnne sammenlignings algoritme blev ikke genkendt af serveren." - -#: lib/Horde/Imap/Client/Socket.php:603 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "Mail serveren understøtter ikke IMAP4rev1 (RFC 3501)." - -#: lib/Horde/Imap/Client/Socket.php:4690 -msgid "The mail server has denied the request." -msgstr "Mail serveren afviste anmodningen." - -#: lib/Horde/Imap/Client/Socket.php:4674 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "Mail serveren rapporterer ødelagt data i din mailmappe." - -#: lib/Horde/Imap/Client/Socket.php:4476 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "" -"Mail serveren var ude af stand til at behandle indholdet af mail beskeden." - -#: lib/Horde/Imap/Client/Socket.php:4429 -#, php-format -msgid "" -"The mail server was unable to parse the contents of the mail message: %s" -msgstr "" -"Mail serveren var ude af stand til at behandle indholdet af mail beskeden: %s" - -#: lib/Horde/Imap/Client/Socket.php:4582 -msgid "The metadata item could not be saved because it is too large." -msgstr "Metadata delen kunne ikke gemmes, da den er for stor." - -#: lib/Horde/Imap/Client/Socket.php:4600 -msgid "" -"The metadata item could not be saved because the maximum number of " -"annotations has been exceeded." -msgstr "" -"Metadata delen kunne ikke gemmes fordi det maksimale antal annotationer er " -"overskredet." - -#: lib/Horde/Imap/Client/Socket.php:4591 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "" -"Metadata delen kunne ikke gemmes fordi serveren ikke understøtter private " -"annotationer." - -#: lib/Horde/Imap/Client/Socket.php:4708 -msgid "The object could not be created because it already exists." -msgstr "Objektet kunne ikke oprettes fordi det allerede findes." - -#: lib/Horde/Imap/Client/Socket.php:4717 -msgid "The object could not be deleted because it does not exist." -msgstr "Objektet kunne ikke slettes fordi det ikke eksisterer." - -#: lib/Horde/Imap/Client/Socket.php:4699 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "Handlingen fejlede fordi pladsen på mail serveren er overskredet." - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:46 -#, php-format -msgid "The server does not support the %s extension." -msgstr "Serveren understøtter ikke %s udvidelsen." - -#: lib/Horde/Imap/Client/Socket.php:4726 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "" -"Den specielle attribut for mail mappen som er anmodet understøttes ikke." - -#: lib/Horde/Imap/Client/Socket.php:4660 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "" -"Der opstod en midlertidig fejl under denne handling. Prøv venligts igen " -"senere." - -#: lib/Horde/Imap/Client/Socket.php:692 -#: lib/Horde/Imap/Client/Socket/Pop3.php:339 -msgid "Unexpected response from server when authenticating." -msgstr "Uventet reaktion fra serveren under godkendelsen." - -#: lib/Horde/Imap/Client/Socket.php:729 -#: lib/Horde/Imap/Client/Socket/Pop3.php:385 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "Ukendt godkendelses metode: %s" - -#: lib/Horde/Imap/Client/Socket.php:4651 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "Du har ikke de nødvendige tilladelser til at udføre denn handlling." diff --git a/lib/horde/locale/da/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/da/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 6e434b7e03a..00000000000 Binary files a/lib/horde/locale/da/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/da/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/da/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index e8859eafb38..00000000000 --- a/lib/horde/locale/da/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,69 +0,0 @@ -# Danish translations for Horde_Mime package. -# Copyright (C) 2014 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime package. -# Erling Preben Hansen , 2013-2014. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2013-10-29 10:13+0100\n" -"PO-Revision-Date: 2014-03-20 21:18+0100\n" -"Last-Translator: Erling Preben Hansen \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: da\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "Dispositions melding" - -#: lib/Horde/Mime/Mail.php:421 -msgid "HTML Version of Message" -msgstr "HTML-udgave af besked" - -#: lib/Horde/Mime/Headers.php:542 -msgid "List-Archive" -msgstr "Liste-Arkivet" - -#: lib/Horde/Mime/Headers.php:537 -msgid "List-Help" -msgstr "Liste-Hjælp" - -#: lib/Horde/Mime/Headers.php:544 -msgid "List-Id" -msgstr "Liste-Id" - -#: lib/Horde/Mime/Headers.php:540 -msgid "List-Owner" -msgstr "Liste-Ejer" - -#: lib/Horde/Mime/Headers.php:541 -msgid "List-Post" -msgstr "Liste-Post" - -#: lib/Horde/Mime/Headers.php:539 -msgid "List-Subscribe" -msgstr "Liste-Abonnér" - -#: lib/Horde/Mime/Headers.php:538 -msgid "List-Unsubscribe" -msgstr "Liste-Afabonnér" - -#: lib/Horde/Mime/Mail.php:419 -msgid "Plaintext Version of Message" -msgstr "Rentekst-udgave af besked" - -#: lib/Horde/Mime/Mdn.php:200 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Beskeden sendt den. %s til %s med emnet \"%s\" er set.\n" -"\n" -"This is no guarantee that the message has been read or understood." diff --git a/lib/horde/locale/de/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/de/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 748d80342ff..00000000000 Binary files a/lib/horde/locale/de/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/de/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/de/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 1b0be5ff6bb..00000000000 --- a/lib/horde/locale/de/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# German translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2017-07-26 12:13+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:37 -msgid "Not Found" -msgstr "Nicht gefunden" - -#: lib/Horde/Exception/PermissionDenied.php:37 -msgid "Permission Denied" -msgstr "Zugriff verweigert" diff --git a/lib/horde/locale/de/LC_MESSAGES/Horde_Idna.mo b/lib/horde/locale/de/LC_MESSAGES/Horde_Idna.mo deleted file mode 100644 index 8d922e4df03..00000000000 Binary files a/lib/horde/locale/de/LC_MESSAGES/Horde_Idna.mo and /dev/null differ diff --git a/lib/horde/locale/de/LC_MESSAGES/Horde_Idna.po b/lib/horde/locale/de/LC_MESSAGES/Horde_Idna.po deleted file mode 100644 index f1708261350..00000000000 --- a/lib/horde/locale/de/LC_MESSAGES/Horde_Idna.po +++ /dev/null @@ -1,71 +0,0 @@ -# German translations for Horde_Idna package. -# Copyright (C) 2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Idna package. -# Jan Schneider , 2017. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Idna\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2017-07-26 12:13+0200\n" -"PO-Revision-Date: 2017-01-24 11:33+0100\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"Language: de\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Idna.php:131 -msgid "ACE label does not contain a valid label string" -msgstr "ACE-Label enthält keinen gültigen Labeltext" - -#: lib/Horde/Idna.php:127 -msgid "Contains a dot" -msgstr "Enthält einen Punkt" - -#: lib/Horde/Idna.php:119 -msgid "Contains disallowed characters" -msgstr "Enthält ungültige Zeichen" - -#: lib/Horde/Idna.php:111 -msgid "Contains hyphen in the third and fourth positions" -msgstr "Enthält Bindestrich an der dritten und vierten Stelle" - -#: lib/Horde/Idna.php:135 -msgid "Does not meet the IDNA BiDi requirements (for right-to-left characters)" -msgstr "" -"Entspricht nicht den IDNA-BiDi-Anforderungen (für rechts-nach-links Zeichen)" - -#: lib/Horde/Idna.php:139 -msgid "Does not meet the IDNA CONTEXTJ requirements" -msgstr "Entspricht nicht den IDNA-CONTEXTJ-Anforderungen" - -#: lib/Horde/Idna.php:94 -msgid "Domain name is empty" -msgstr "Domainname ist leer" - -#: lib/Horde/Idna.php:99 -msgid "Domain name is too long" -msgstr "Domainname ist zu lang" - -#: lib/Horde/Idna.php:107 -msgid "Ends with a hyphen" -msgstr "Endet mit einem Bindestrich" - -#: lib/Horde/Idna.php:123 -msgid "Starts with \"xn--\" but does not contain valid Punycode" -msgstr "Beginnt mit \"xn--\" aber enthält keinen gültigen Punycode" - -#: lib/Horde/Idna.php:115 -msgid "Starts with a combining mark" -msgstr "Beginnt mit einem Kombinationszeichen" - -#: lib/Horde/Idna.php:103 -msgid "Starts with a hyphen" -msgstr "Beginnt mit einem Bindestrich" - -#: lib/Horde/Idna.php:143 -msgid "Unknown error" -msgstr "Unbekannter Fehler" diff --git a/lib/horde/locale/de/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/de/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index dd3e96b5203..00000000000 Binary files a/lib/horde/locale/de/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/de/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/de/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index cd512d8babb..00000000000 --- a/lib/horde/locale/de/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,291 +0,0 @@ -# German translations for Horde_Imap_Client package. -# Copyright 2012-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# Jan Schneider , 2012-2015. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2017-07-26 12:13+0200\n" -"PO-Revision-Date: 2015-12-29 17:59+0100\n" -"Last-Translator: Jan Schneider \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: de\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:34 -#, php-format -msgid "%s not supported on POP3 servers." -msgstr "%s wird auf POP3-Servern nicht unterstützt." - -#: lib/Horde/Imap/Client/Socket.php:5035 -msgid "Authentication credentials have expired." -msgstr "Die Anmeldedaten sind nicht mehr gültig." - -#: lib/Horde/Imap/Client/Socket.php:747 lib/Horde/Imap/Client/Socket.php:5019 -#: lib/Horde/Imap/Client/Socket/Pop3.php:441 -#: lib/Horde/Imap/Client/Socket/Pop3.php:460 -#: lib/Horde/Imap/Client/Socket/Pop3.php:486 -#: lib/Horde/Imap/Client/Socket/Pop3.php:498 -msgid "Authentication failed." -msgstr "Anmeldung fehlgeschlagen." - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:158 -#: lib/Horde/Imap/Client/Auth/Scram.php:124 -msgid "Authentication failure." -msgstr "Anmeldung fehlgeschlagen." - -#: lib/Horde/Imap/Client/Socket.php:5027 -msgid "Authentication was successful, but authorization failed." -msgstr "" -"Die Anmeldung war erfolgreich aber die Autorisierung ist fehlgeschlagen." - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:44 -msgid "Bad tagged response." -msgstr "Ungültige getaggte Antwort." - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:45 -msgid "Cannot convert search query text to new charset" -msgstr "" -"Der Suchtext konnte nicht in den benötigten Zeichensatz übersetzt werden." - -#: lib/Horde/Imap/Client/Base.php:1924 lib/Horde/Imap/Client/Base.php:1987 -msgid "Cannot expunge read-only mailbox." -msgstr "Nur-Lesen-Ordner können nicht aufgeräumt werden." - -#: lib/Horde/Imap/Client/Socket.php:4811 -msgid "Charset used in search query is not supported on the mail server." -msgstr "" -"Der Zeichensatz, der in der Suchanfrage benutzt wurde, wird von dem E-Mail-" -"Server nicht unterstützt." - -#: lib/Horde/Imap/Client/Socket.php:1240 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "Ordner \"%s\" konnte nicht geöffnet werden." - -#: lib/Horde/Imap/Client/Socket.php:358 lib/Horde/Imap/Client/Socket.php:400 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "Sichere TLS-Verbindung zum IMAP-Server kann nicht hergestellt werden." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:219 -#: lib/Horde/Imap/Client/Socket/Pop3.php:233 -msgid "Could not open secure connection to the POP3 server." -msgstr "Sichere Verbindung zum POP3-Server kann nicht hergestellt werden." - -#: lib/Horde/Imap/Client/Socket.php:4919 -msgid "Could not save message data because it is too large." -msgstr "" -"Nachrichtendaten konnten nicht gespeichert werden, weil sie zu groß sind." - -#: lib/Horde/Imap/Client/Socket.php:4910 -msgid "Could not save message on server." -msgstr "Die Nachricht konnte nicht auf dem E-Mail-Server gespeichert werden." - -#: lib/Horde/Imap/Client/Socket.php:606 -#: lib/Horde/Imap/Client/Socket/Pop3.php:324 -msgid "Error connecting to mail server." -msgstr "Verbindung zum E-Mail-Server fehlgeschlagen." - -#: lib/Horde/Imap/Client/Utf7imap.php:128 -#: lib/Horde/Imap/Client/Utf7imap.php:156 -#: lib/Horde/Imap/Client/Utf7imap.php:163 -#: lib/Horde/Imap/Client/Utf7imap.php:225 -#: lib/Horde/Imap/Client/Utf7imap.php:245 -#: lib/Horde/Imap/Client/Utf7imap.php:252 -#: lib/Horde/Imap/Client/Utf7imap.php:263 -#: lib/Horde/Imap/Client/Utf7imap.php:272 -msgid "Error converting UTF7-IMAP string." -msgstr "Fehler beim Umwandeln eines UTF7-IMAP-Strings." - -#: lib/Horde/Imap/Client/Socket.php:4467 -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:83 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:214 -#: lib/Horde/Imap/Client/Socket/Pop3.php:1382 -msgid "Error when communicating with the mail server." -msgstr "Fehler während der Kommunikation mit dem E-Mail-Server." - -#: lib/Horde/Imap/Client/Socket.php:4605 -msgid "IMAP Server closed the connection." -msgstr "Der IMAP-Server hat die Verbindung unterbrochen." - -#: lib/Horde/Imap/Client/Socket.php:4591 -msgid "IMAP error reported by server." -msgstr "Der E-Mail-Server hat einen IMAP-Fehler gemeldet." - -#: lib/Horde/Imap/Client/Socket.php:4009 -#, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "Ungültiger METADATA-Eintrag: \"%s\"" - -#: lib/Horde/Imap/Client/Socket.php:4102 -#, php-format -msgid "Invalid METADATA value type \"%s\"." -msgstr "Ungültiger METADATA-Wertetyp \"%s\"." - -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:148 -msgid "Mail server closed the connection unexpectedly." -msgstr "Der E-Mail-Server hat die Verbindung unerwartet unterbrochen." - -#: lib/Horde/Imap/Client/Socket.php:573 -msgid "Mail server denied authentication." -msgstr "Der E-Mail-Server hat die Authentifizierung verweigert." - -#: lib/Horde/Imap/Client/Base.php:2257 lib/Horde/Imap/Client/Base.php:2536 -#: lib/Horde/Imap/Client/Base.php:2808 lib/Horde/Imap/Client/Base.php:2893 -msgid "Mailbox does not support mod-sequences." -msgstr "Der Ordner unterstützt keine Mod-Sequences." - -#: lib/Horde/Imap/Client/Socket.php:370 -#: lib/Horde/Imap/Client/Socket/Pop3.php:201 -msgid "No password provided." -msgstr "Kein Passwort angegeben." - -#: lib/Horde/Imap/Client/Socket.php:498 -msgid "No supported IMAP authentication method could be found." -msgstr "" -"Es wurde keine unterstützte Authentifizierungsmethode für IMAP gefunden." - -#: lib/Horde/Imap/Client/Socket.php:5043 -msgid "Operation failed due to a lack of a secure connection." -msgstr "" -"Die Operation ist wegen einer fehlenden sicheren Verbindung fehlgeschlagen." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1448 -msgid "POP3 error reported by server." -msgstr "Der E-Mail-Server hat einen POP3-Fehler gemeldet." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:295 -msgid "POP3 server denied authentication." -msgstr "Der POP3-Server hat die Authentifizierung zurückgewiesen." - -#: lib/Horde/Imap/Client/Socket.php:5011 -msgid "Remote server is temporarily unavailable." -msgstr "Der E-Mail-Server ist zur Zeit nicht verfügbar." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:75 -msgid "Server closed the connection unexpectedly." -msgstr "Der E-Mail-Server hat die Verbindung unerwartet unterbrochen." - -#: lib/Horde/Imap/Client/Socket.php:388 -msgid "Server does not support TLS connections." -msgstr "Der E-Mail-Server unterstützt keine TLS-Verbindungen." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:219 -msgid "Server does not support secure connections." -msgstr "Der E-Mail-Server unterstützt keine sicheren Verbindungen." - -#: lib/Horde/Imap/Client/Socket.php:809 -#: lib/Horde/Imap/Client/Socket/Pop3.php:508 -msgid "Server failed verification check." -msgstr "Bestätigung des E-Mail-Servers fehlgeschlagen." - -#: lib/Horde/Imap/Client/Socket.php:626 -msgid "Server rejected connection." -msgstr "Der E-Mail-Server hat die Verbindung abgelehnt." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:47 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:64 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:110 -msgid "Server write error." -msgstr "Server-Schreibfehler." - -#: lib/Horde/Imap/Client/Socket.php:4964 -msgid "The comparison algorithm was not recognized by the server." -msgstr "Der Vergleichsalgorithmus wurde vom E-Mail-Server nicht erkannt." - -#: lib/Horde/Imap/Client/Socket.php:635 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "Der E-Mail-Server unterstützt kein IMAP4rev1 (RFC 3501)." - -#: lib/Horde/Imap/Client/Socket.php:5092 -msgid "The mail server has denied the request." -msgstr "Der E-Mail-Server hat die Anfrage abgelehnt." - -#: lib/Horde/Imap/Client/Socket.php:5074 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "Der E-Mail-Server hat beschädigte Daten in Ihrem Ordner gemeldet." - -#: lib/Horde/Imap/Client/Socket.php:4876 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "Der E-Mail-Server konnte den Inhalt der Nachricht nicht auswerten." - -#: lib/Horde/Imap/Client/Socket.php:4827 -#, php-format -msgid "" -"The mail server was unable to parse the contents of the mail message: %s" -msgstr "Der E-Mail-Server konnte den Inhalt der Nachricht nicht auswerten: %s" - -#: lib/Horde/Imap/Client/Socket.php:4982 -msgid "The metadata item could not be saved because it is too large." -msgstr "" -"Der Metadaten-Eintrag konnte nicht gespeichert werden, weil er zu groß ist." - -#: lib/Horde/Imap/Client/Socket.php:5000 -msgid "" -"The metadata item could not be saved because the maximum number of " -"annotations has been exceeded." -msgstr "" -"Der Metadaten-Eintrag konnte nicht gespeichert werden, weil die maximale " -"Anzahl an Vermerken erschöpft ist." - -#: lib/Horde/Imap/Client/Socket.php:4991 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "" -"Der Metadaten-Eintrag konnte nicht gespeichert werden, weil der E-Mail-" -"Server keine privaten Vermerke unterstützt." - -#: lib/Horde/Imap/Client/Socket.php:5110 -msgid "The object could not be created because it already exists." -msgstr "" -"Das Element konnte nicht gespeichert werden, weil es bereits existiert." - -#: lib/Horde/Imap/Client/Socket.php:5119 -msgid "The object could not be deleted because it does not exist." -msgstr "Das Element konnte nicht gelöscht werden, weil es nicht existiert." - -#: lib/Horde/Imap/Client/Socket.php:5101 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "" -"Die Operation ist fehlgeschlagen, weil das Speicherplatzkontingent auf dem E-" -"Mail-Server erschöpft ist." - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:46 -#, php-format -msgid "The server does not support the %s extension." -msgstr "Der Server unterstützt die %s-Erweiterung nicht." - -#: lib/Horde/Imap/Client/Socket.php:5128 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "" -"Das Attribut für spezielle Nutzung wird von dem Ordner nicht unterstützt." - -#: lib/Horde/Imap/Client/Socket.php:5060 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "" -"Bei dieser Aktion ist ein vorübergehender Fehler aufgetreten. Bitte " -"versuchen Sie es später noch einmal." - -#: lib/Horde/Imap/Client/Socket.php:723 -#: lib/Horde/Imap/Client/Socket/Pop3.php:379 -msgid "Unexpected response from server when authenticating." -msgstr "Unerwartete Antwort vom E-Mail-Server während der Anmeldung." - -#: lib/Horde/Imap/Client/Socket.php:839 -#: lib/Horde/Imap/Client/Socket/Pop3.php:518 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "Unbekannte Authentifizierungsmethode: %s" - -#: lib/Horde/Imap/Client/Socket.php:5051 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "Sie haben nicht die nötigen Rechte, um diese Aktion durchzuführen." diff --git a/lib/horde/locale/de/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/de/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 6e115022172..00000000000 Binary files a/lib/horde/locale/de/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/de/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/de/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 679619586ec..00000000000 --- a/lib/horde/locale/de/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,42 +0,0 @@ -# German translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2015-01-08 11:22+0100\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "Empfangsbestätigung" - -#: lib/Horde/Mime/Mail.php:439 -msgid "HTML Version of Message" -msgstr "HTML-Version der Nachricht" - -#: lib/Horde/Mime/Mail.php:437 -msgid "Plaintext Version of Message" -msgstr "Textversion der Nachricht" - -#: lib/Horde/Mime/Mdn.php:201 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Die Nachricht mit dem Betreff \"%3$s\", die am %1$s an %2$s geschickt wurde, " -"ist angezeigt worden.\n" -"\n" -"Das heißt nicht, dass die Nachricht auch gelesen oder verstanden wurde." diff --git a/lib/horde/locale/el/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/el/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 3649388d7eb..00000000000 Binary files a/lib/horde/locale/el/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/el/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/el/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 586e8a2dd4e..00000000000 --- a/lib/horde/locale/el/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,27 +0,0 @@ -# Greek translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2015-10-02 12:08+0200\n" -"Last-Translator: Antonis Limperis \n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: el\n" -"X-Generator: Poedit 1.7.1\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "Δεν Υπάρχει" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "Δεν υπάρχουν δικαιώματα" diff --git a/lib/horde/locale/el/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/el/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index 36a9cbc1d5b..00000000000 Binary files a/lib/horde/locale/el/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/el/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/el/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index 9714263f047..00000000000 --- a/lib/horde/locale/el/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,283 +0,0 @@ -# German translations for Horde_Imap_Client package. -# Copyright 2012-2015 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# Jan Schneider , 2012-2014. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2015-03-24 10:40+0100\n" -"PO-Revision-Date: 2015-10-02 15:23+0200\n" -"Last-Translator: Antonis Limperis \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: de\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 1.7.1\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:34 -#, php-format -msgid "%s not supported on POP3 servers." -msgstr "%s δεν υποστηρίζεται σε διακομιστές POP3." - -#: lib/Horde/Imap/Client/Socket.php:4922 -msgid "Authentication credentials have expired." -msgstr "Tα διαπιστευτήρια ελέγχου ταυτότητας έχουν λήξει." - -#: lib/Horde/Imap/Client/Socket.php:725 lib/Horde/Imap/Client/Socket.php:4906 -#: lib/Horde/Imap/Client/Socket/Pop3.php:440 -#: lib/Horde/Imap/Client/Socket/Pop3.php:459 -msgid "Authentication failed." -msgstr "Η πιστοποίηση απέτυχε." - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:158 -msgid "Authentication failure." -msgstr "Αποτυχία πιστοποίησης" - -#: lib/Horde/Imap/Client/Socket.php:4914 -msgid "Authentication was successful, but authorization failed." -msgstr "Η πιστοποίηση ήταν επιτυχής, αλλά απέτυχε η εξουσιοδότηση." - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:44 -msgid "Bad tagged response." -msgstr "Απάντηση κακής ετικέτας." - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:45 -msgid "Cannot convert search query text to new charset" -msgstr "Αδυναμία μετατροπής του κειμένου αναζήτησης στο νέο σύνολο χαρακτήρων" - -#: lib/Horde/Imap/Client/Base.php:1920 lib/Horde/Imap/Client/Base.php:1983 -msgid "Cannot expunge read-only mailbox." -msgstr "" -"Δεν είναι δυνατή η οριστική διαγραφή σε γραμματοθυρίδα μόνο για ανάγνωση" - -#: lib/Horde/Imap/Client/Socket.php:4698 -msgid "Charset used in search query is not supported on the mail server." -msgstr "" -"Το σύνολο χαρακτήρων που χρησιμοποιείται στην αναζήτηση δεν υποστηρίζεται " -"από το διακομιστή αλληλογραφίας." - -#: lib/Horde/Imap/Client/Socket.php:1139 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "Δεν ήταν δυνατό το άνοιγμα της γραμματοθυρίδας \"% s \"." - -#: lib/Horde/Imap/Client/Socket.php:357 lib/Horde/Imap/Client/Socket.php:399 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "" -"Δεν θα ήταν δυνατό το άνοιγμα ασφαλούς σύνδεσης TLS προς τον διακομιστή IMAP." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:218 -#: lib/Horde/Imap/Client/Socket/Pop3.php:232 -msgid "Could not open secure connection to the POP3 server." -msgstr "Sichere Verbindung zum POP3-Server kann nicht hergestellt werden." - -#: lib/Horde/Imap/Client/Socket.php:4806 -msgid "Could not save message data because it is too large." -msgstr "" -"Δεν ήταν δυνατή η αποθήκευση των δεδομένων του μηνύματος, επειδή είναι πολύ " -"μεγάλο." - -#: lib/Horde/Imap/Client/Socket.php:4797 -msgid "Could not save message on server." -msgstr "Δεν ήταν δυνατή η αποθήκευση του μηνύματος στο διακομιστή." - -#: lib/Horde/Imap/Client/Socket.php:580 -#: lib/Horde/Imap/Client/Socket/Pop3.php:323 -msgid "Error connecting to mail server." -msgstr "Σφάλμα κατά τη σύνδεση στον διακομιστή e-mail." - -#: lib/Horde/Imap/Client/Utf7imap.php:128 -#: lib/Horde/Imap/Client/Utf7imap.php:156 -#: lib/Horde/Imap/Client/Utf7imap.php:163 -#: lib/Horde/Imap/Client/Utf7imap.php:225 -#: lib/Horde/Imap/Client/Utf7imap.php:245 -#: lib/Horde/Imap/Client/Utf7imap.php:252 -#: lib/Horde/Imap/Client/Utf7imap.php:263 -#: lib/Horde/Imap/Client/Utf7imap.php:272 -msgid "Error converting UTF7-IMAP string." -msgstr "Σφάλμα κατά τη μετατροπή της συμβολοσειράς UTF7-IMAP ." - -#: lib/Horde/Imap/Client/Socket.php:4360 -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:83 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:207 -#: lib/Horde/Imap/Client/Socket/Pop3.php:1337 -msgid "Error when communicating with the mail server." -msgstr "Σφάλμα κατά την επικοινωνία με το διακομιστή αλληλογραφίας." - -#: lib/Horde/Imap/Client/Socket.php:4492 -msgid "IMAP Server closed the connection." -msgstr "Der IMAP-Server hat die Verbindung unterbrochen." - -#: lib/Horde/Imap/Client/Socket.php:4478 -msgid "IMAP error reported by server." -msgstr "Ο διακομιστής ανέφερε σφάλμα IMAP." - -#: lib/Horde/Imap/Client/Socket.php:3904 -#, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "Άκυρη καταχώρηση μεταδεδομένων: \"% s \"." - -#: lib/Horde/Imap/Client/Socket.php:3997 -#, php-format -msgid "Invalid METADATA value type \"%s\"." -msgstr "Μη έγκυρη τιμή μεταδεδομένων \"% s \"." - -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:148 -msgid "Mail server closed the connection unexpectedly." -msgstr "Ο Διακομιστής αλληλογραφίας έκλεισε τη σύνδεση απροσδόκητα." - -#: lib/Horde/Imap/Client/Socket.php:547 -msgid "Mail server denied authentication." -msgstr "Ο διακομιστής αλληλογραφίας αρνήθηκε την πιστοποίηση." - -#: lib/Horde/Imap/Client/Base.php:2233 lib/Horde/Imap/Client/Base.php:2518 -#: lib/Horde/Imap/Client/Base.php:2790 lib/Horde/Imap/Client/Base.php:2875 -msgid "Mailbox does not support mod-sequences." -msgstr "Η γραμματοθυρίδα δεν υποστηρίζει mod-ακολουθίες." - -#: lib/Horde/Imap/Client/Socket.php:369 -#: lib/Horde/Imap/Client/Socket/Pop3.php:200 -msgid "No password provided." -msgstr "Δεν δόθηκε κωδικός πρόσβασης." - -#: lib/Horde/Imap/Client/Socket.php:472 -msgid "No supported IMAP authentication method could be found." -msgstr "Δεν μπορεί να εντοπιστεί η υποστηριζόμενη IMAP μέθοδος πιστοποίησης." - -#: lib/Horde/Imap/Client/Socket.php:4930 -msgid "Operation failed due to a lack of a secure connection." -msgstr "Η λειτουργία απέτυχε λόγω της έλλειψης μιας ασφαλούς σύνδεσης." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1403 -msgid "POP3 error reported by server." -msgstr "Ο διακομιστής ανέφερε σφάλμα POP3." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:294 -msgid "POP3 server denied authentication." -msgstr "Ο διακομιστής POP3 αρνήθηκε την πιστοποίηση." - -#: lib/Horde/Imap/Client/Socket.php:4898 -msgid "Remote server is temporarily unavailable." -msgstr "O απομακρυσμένο διακομιστής δεν είναι διαθέσιμος προσωρινά." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:75 -msgid "Server closed the connection unexpectedly." -msgstr "Ο διακομιστής έκλεισε τη σύνδεση απροσδόκητα." - -#: lib/Horde/Imap/Client/Socket.php:387 -msgid "Server does not support TLS connections." -msgstr "Ο διακομιστής δεν υποστηρίζει συνδέσεις TLS." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:218 -msgid "Server does not support secure connections." -msgstr "Ο διακομιστής δεν υποστηρίζει ασφαλείς συνδέσεις." - -#: lib/Horde/Imap/Client/Socket.php:600 -msgid "Server rejected connection." -msgstr "Ο διακομιστής απέρριψε τη σύνδεση." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:47 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:64 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:110 -msgid "Server write error." -msgstr "Σφάλμα εγγραφής στο διακομιστή." - -#: lib/Horde/Imap/Client/Socket.php:4851 -msgid "The comparison algorithm was not recognized by the server." -msgstr "Ο αλγόριθμος σύγκρισης δεν αναγνωρίζεται από το διακομιστή." - -#: lib/Horde/Imap/Client/Socket.php:609 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "Ο διακομιστής αλληλογραφίας δεν υποστηρίζει IMAP4rev1 (RFC 3501)." - -#: lib/Horde/Imap/Client/Socket.php:4979 -msgid "The mail server has denied the request." -msgstr "Ο διακομιστής αλληλογραφίας αρνήθηκε το αίτημα." - -#: lib/Horde/Imap/Client/Socket.php:4961 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "" -"Ο διακομιστής αλληλογραφίας η ανέφερε κατεστραμένα δεδομένα στη " -"γραμματοθυρίδα σας." - -#: lib/Horde/Imap/Client/Socket.php:4763 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "" -"Ο διακομιστής αλληλογραφίας δεν ήταν σε θέση να αναλύσει το περιεχόμενο του " -"μηνύματος e-mail" - -#: lib/Horde/Imap/Client/Socket.php:4714 -#, php-format -msgid "" -"The mail server was unable to parse the contents of the mail message: %s" -msgstr "" -"Ο διακομιστής αλληλογραφίας δεν ήταν σε θέση να αναλύσει το περιεχόμενο του " -"μηνύματος e-mail: %s" - -#: lib/Horde/Imap/Client/Socket.php:4869 -msgid "The metadata item could not be saved because it is too large." -msgstr "" -"Το στοιχείο μεταδεδομένων δεν ήταν δυνατό να αποθηκευτεί επειδή είναι πολύ " -"μεγάλο." - -#: lib/Horde/Imap/Client/Socket.php:4878 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "" -"Το στοιχείο μεταδεδομένων δεν ήταν δυνατό να αποθηκευτεί επειδή ο " -"διακομιστής δεν υποστηρίζει ιδιωτικούς σχολιασμούς." - -#: lib/Horde/Imap/Client/Socket.php:4997 -msgid "The object could not be created because it already exists." -msgstr "" -"Το στοιχείο μεταδεδομένων δεν ήταν δυνατό να δημιουργηθεί επειδή υπάρχει ήδη" - -#: lib/Horde/Imap/Client/Socket.php:5006 -msgid "The object could not be deleted because it does not exist." -msgstr "Το αντικείμενο δεν θα μπορούσε να διαγραφεί επειδή δεν υπάρχει." - -#: lib/Horde/Imap/Client/Socket.php:4988 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "" -"Η λειτουργία απέτυχε επειδή ο χώρος έχει ξεπεραστεί στον διακομιστή " -"ηλεκτρονικού ταχυδρομείου." - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:46 -#, php-format -msgid "The server does not support the %s extension." -msgstr "Ο διακομιστής δεν υποστηρίζει την επέκταση%s." - -#: lib/Horde/Imap/Client/Socket.php:5015 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "" -"Το χαρακτηριστικό ειδικής χρήσης που ζητήθηκε για το γραμματοκιβώτιο δεν " -"υποστηρίζεται." - -#: lib/Horde/Imap/Client/Socket.php:4947 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "" -"Υπήρξε ένα προσωρινό πρόβλημα κατά την προσπάθεια αυτής της λειτουργίας. " -"Παρακαλώ προσπαθείστε ξανά αργότερα." - -#: lib/Horde/Imap/Client/Socket.php:701 -#: lib/Horde/Imap/Client/Socket/Pop3.php:378 -msgid "Unexpected response from server when authenticating." -msgstr "Μη αναμενόμενη απόκριση από το διακομιστή κατά την πιστοποίηση." - -#: lib/Horde/Imap/Client/Socket.php:757 -#: lib/Horde/Imap/Client/Socket/Pop3.php:473 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "Άγνωστη μέθοδος πιστοποίησης: %s" - -#: lib/Horde/Imap/Client/Socket.php:4938 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "Δεν έχετε επαρκή δικαιώματα για την εκτέλεση αυτής της λειτουργίας." diff --git a/lib/horde/locale/el/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/el/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index ed99475a778..00000000000 Binary files a/lib/horde/locale/el/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/el/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/el/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index da14ecabf3c..00000000000 --- a/lib/horde/locale/el/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,76 +0,0 @@ -# Greek translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2015-10-02 16:01+0200\n" -"Last-Translator: Antonis Limperis \n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: el\n" -"X-Generator: Poedit 1.7.1\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Ειδοποίηση Διάθεσης" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "Έκδοση HTML του μηνύματος" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Μη έγκυρος χαρακτήρας στο e-mail: %s." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Λίστα θεμάτων Βοήθειας" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -#, fuzzy -msgid "List-Subscribe" -msgstr "Υποδείκτης" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "Έκδοση απλού κειμένου του μηνύματος" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Το μήνυμα που στάλθηκε στις %s στον %s με θέμα %s εμφανίσθηκε.\n" -"Αυτό δεν αποτελεί επιβεβαίωση ότι διαβάσθηκε και έγινε κατανοητό." diff --git a/lib/horde/locale/es/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/es/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index b43eaf6179a..00000000000 Binary files a/lib/horde/locale/es/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/es/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/es/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 93f76a6dff5..00000000000 --- a/lib/horde/locale/es/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,27 +0,0 @@ -# Spanish translations for Horde_Exception package. -# Copyright (C) 2013 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception package. -# Automatically generated, 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception \n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-01-17 12:38+0100\n" -"PO-Revision-Date: 2013-06-11 20:26+0200\n" -"Last-Translator: Manuel P. Ayala , Juan C. Blanco " -"\n" -"Language-Team: i18n@lists.horde.org\n" -"Language: es\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "No encontrado" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Permiso denegado" diff --git a/lib/horde/locale/es/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/es/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index efb29cb138b..00000000000 Binary files a/lib/horde/locale/es/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/es/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/es/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index 14a8e33e3ca..00000000000 --- a/lib/horde/locale/es/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,276 +0,0 @@ -# Spanish translations for Horde_Imap_Client package. -# Copyright (C) 2014 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# Automatically generated, 2014. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2014-06-12 16:24+0200\n" -"PO-Revision-Date: 2014-06-16 09:05+0100\n" -"Last-Translator: Manuel P. Ayala , Juan C. Blanco " -"\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"Language: es\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:34 -#, php-format -msgid "%s not supported on POP3 servers." -msgstr "%s no está soportado en servidores POP3." - -#: lib/Horde/Imap/Client/Socket.php:4742 -msgid "Authentication credentials have expired." -msgstr "Las credenciales de autentificación han caducado." - -#: lib/Horde/Imap/Client/Socket.php:4726 -msgid "Authentication failed." -msgstr "Falló la autentificación." - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:158 -msgid "Authentication failure." -msgstr "Fallo de autentificación." - -#: lib/Horde/Imap/Client/Socket.php:4734 -msgid "Authentication was successful, but authorization failed." -msgstr "La autentificación fue correcta pero falló la autorización." - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:44 -msgid "Bad tagged response." -msgstr "Respuesta etiquetada incorrecta." - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:45 -msgid "Cannot convert search query text to new charset" -msgstr "" -"No se puede convertir el texto de búsqueda al nuevo juego de caracteres" - -#: lib/Horde/Imap/Client/Base.php:1873 lib/Horde/Imap/Client/Base.php:1936 -msgid "Cannot expunge read-only mailbox." -msgstr "No se puede borrar un buzón de sólo lectura." - -#: lib/Horde/Imap/Client/Socket.php:4518 -msgid "Charset used in search query is not supported on the mail server." -msgstr "" -"El servidor de correo no admite el juego de caracteres de la consulta de " -"búsqueda." - -#: lib/Horde/Imap/Client/Socket.php:1084 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "No se pudo abrir el buzón \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:357 lib/Horde/Imap/Client/Socket.php:398 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "No se puede iniciar una conexión TLS segura al servidor IMAP" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:207 -#: lib/Horde/Imap/Client/Socket/Pop3.php:221 -msgid "Could not open secure connection to the POP3 server." -msgstr "No se puede iniciar una conexión segura al servidor POP3" - -#: lib/Horde/Imap/Client/Socket.php:4626 -msgid "Could not save message data because it is too large." -msgstr "No se pueden guardar los datos del mensaje ya que es demasiado largo." - -#: lib/Horde/Imap/Client/Socket.php:4617 -msgid "Could not save message on server." -msgstr "No se puede guardar el mensaje en el servidor." - -#: lib/Horde/Imap/Client/Socket.php:579 -#: lib/Horde/Imap/Client/Socket/Pop3.php:301 -msgid "Error connecting to mail server." -msgstr "Error conectando al servidor de correo." - -#: lib/Horde/Imap/Client/Utf7imap.php:128 -#: lib/Horde/Imap/Client/Utf7imap.php:156 -#: lib/Horde/Imap/Client/Utf7imap.php:163 -#: lib/Horde/Imap/Client/Utf7imap.php:225 -#: lib/Horde/Imap/Client/Utf7imap.php:245 -#: lib/Horde/Imap/Client/Utf7imap.php:252 -#: lib/Horde/Imap/Client/Utf7imap.php:263 -#: lib/Horde/Imap/Client/Utf7imap.php:272 -msgid "Error converting UTF7-IMAP string." -msgstr "Error convirtiendo cadena UTF7-IMAP." - -#: lib/Horde/Imap/Client/Socket.php:4186 -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:77 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:189 -#: lib/Horde/Imap/Client/Socket/Pop3.php:1211 -msgid "Error when communicating with the mail server." -msgstr "Error al comunicar con el servidor de correo." - -#: lib/Horde/Imap/Client/Socket.php:4305 -msgid "IMAP Server closed the connection." -msgstr "El servidor IMAP cerró la conexión." - -#: lib/Horde/Imap/Client/Socket.php:4291 -msgid "IMAP error reported by server." -msgstr "Error IMAP indicado por el servidor." - -#: lib/Horde/Imap/Client/Socket.php:3775 -#, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "Entrada de METADATOS inválida: \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:3863 -#, php-format -msgid "Invalid METADATA value type \"%s\"." -msgstr "Tipo de valor de METADATOS inválido \"%s\"." - -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:130 -msgid "Mail server closed the connection unexpectedly." -msgstr "El servidor de correo cerró la conexión inesperadamente." - -#: lib/Horde/Imap/Client/Socket.php:547 -msgid "Mail server denied authentication." -msgstr "El servidor denegó la autentificación." - -#: lib/Horde/Imap/Client/Base.php:2188 lib/Horde/Imap/Client/Base.php:2477 -#: lib/Horde/Imap/Client/Base.php:2745 lib/Horde/Imap/Client/Base.php:2830 -msgid "Mailbox does not support mod-sequences." -msgstr "El buzón no admite mod-sequences." - -#: lib/Horde/Imap/Client/Socket.php:369 -#: lib/Horde/Imap/Client/Socket/Pop3.php:189 -msgid "No password provided." -msgstr "No se ha indicado una contraseña." - -#: lib/Horde/Imap/Client/Socket.php:474 -msgid "No supported IMAP authentication method could be found." -msgstr "No se pudo encontrar un método de autentificación IMAP admitido." - -#: lib/Horde/Imap/Client/Socket.php:4750 -msgid "Operation failed due to a lack of a secure connection." -msgstr "La operación falló por la inexistencia de una conexión segura." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1270 -msgid "POP3 error reported by server." -msgstr "Error POP3 indicado por el servidor." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:273 -msgid "POP3 server denied authentication." -msgstr "El servidor POP3 denegó la autentificación." - -#: lib/Horde/Imap/Client/Socket.php:4718 -msgid "Remote server is temporarily unavailable." -msgstr "El servidor remoto no está disponible temporalmente." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:69 -msgid "Server closed the connection unexpectedly." -msgstr "El servidor cerró la conexión inesperadamente." - -#: lib/Horde/Imap/Client/Socket.php:386 -msgid "Server does not support TLS connections." -msgstr "El servidor no admite conexiones TLS." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:207 -msgid "Server does not support secure connections." -msgstr "El servidor no admite conexiones seguras." - -#: lib/Horde/Imap/Client/Socket.php:599 -msgid "Server rejected connection." -msgstr "El servidor rechazó la conexión." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:46 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:54 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:85 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:94 -msgid "Server write error." -msgstr "Error de escritura en el servidor." - -#: lib/Horde/Imap/Client/Socket.php:4671 -msgid "The comparison algorithm was not recognized by the server." -msgstr "El servidor no reconoció el algoritmo de comparación." - -#: lib/Horde/Imap/Client/Socket.php:608 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "El servidor no admite IMAP4rev1 (RFC 3501)." - -#: lib/Horde/Imap/Client/Socket.php:4799 -msgid "The mail server has denied the request." -msgstr "El servidor de correo ha denegado la petición." - -#: lib/Horde/Imap/Client/Socket.php:4781 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "El servidor de correo informa que hay datos corruptos en su buzón." - -#: lib/Horde/Imap/Client/Socket.php:4583 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "El servidor no pudo procesar los contenidos del mensaje de correo." - -#: lib/Horde/Imap/Client/Socket.php:4534 -#, php-format -msgid "" -"The mail server was unable to parse the contents of the mail message: %s" -msgstr "El servidor no pudo procesar los contenidos del mensaje de correo: %s" - -#: lib/Horde/Imap/Client/Socket.php:4689 -msgid "The metadata item could not be saved because it is too large." -msgstr "El elemento de metadatos no se pudo guardar ya que es demasiado largo." - -#: lib/Horde/Imap/Client/Socket.php:4707 -msgid "" -"The metadata item could not be saved because the maximum number of " -"annotations has been exceeded." -msgstr "" -"El elemento de metadatos no se pudo guardar ya que se ha superado el número " -"máximo de anotaciones." - -#: lib/Horde/Imap/Client/Socket.php:4698 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "" -"El elemento de metadatos no se pudo guardar ya que el servidor no admite " -"anotaciones privadas." - -#: lib/Horde/Imap/Client/Socket.php:4817 -msgid "The object could not be created because it already exists." -msgstr "No se puede crear el objeto porque ya existe." - -#: lib/Horde/Imap/Client/Socket.php:4826 -msgid "The object could not be deleted because it does not exist." -msgstr "No se puede borrar el objeto porque no existe." - -#: lib/Horde/Imap/Client/Socket.php:4808 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "" -"La operación ha fallado porque ha excedido su cuota en el servidor de correo." - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:46 -#, php-format -msgid "The server does not support the %s extension." -msgstr "El servidor no admite la extensión %s." - -#: lib/Horde/Imap/Client/Socket.php:4835 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "El atributo de uso-especial solicitado para el buzón no se admite." - -#: lib/Horde/Imap/Client/Socket.php:4767 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "" -"Se ha producido un error temporal al intentar esta operación. Por favor, " -"vuelva a intentarlo mas adelante." - -#: lib/Horde/Imap/Client/Socket.php:697 -#: lib/Horde/Imap/Client/Socket/Pop3.php:356 -msgid "Unexpected response from server when authenticating." -msgstr "Respuesta inesperada del servidor al autentificar." - -#: lib/Horde/Imap/Client/Socket.php:734 -#: lib/Horde/Imap/Client/Socket/Pop3.php:402 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "Método de autentificación desconocido: %s" - -#: lib/Horde/Imap/Client/Socket.php:4758 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "Carece de los permisos adecuados para ejecutar esta operación." diff --git a/lib/horde/locale/es/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/es/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 963f32c4690..00000000000 Binary files a/lib/horde/locale/es/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/es/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/es/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index d21e86534af..00000000000 --- a/lib/horde/locale/es/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,70 +0,0 @@ -# Spanish translations for Horde_Mime package. -# Copyright (C) 2013 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime package. -# Automatically generated, 2013. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime \n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2013-07-16 21:24+0200\n" -"PO-Revision-Date: 2013-06-11 20:26+0200\n" -"Last-Translator: Manuel P. Ayala , Juan C. Blanco " -"\n" -"Language-Team: i18n@lists.horde.org\n" -"Language: es\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "Notificación de consulta" - -#: lib/Horde/Mime/Mail.php:421 -msgid "HTML Version of Message" -msgstr "Versión HTML del mensaje" - -#: lib/Horde/Mime/Headers.php:540 -msgid "List-Archive" -msgstr "List-Archive" - -#: lib/Horde/Mime/Headers.php:535 -msgid "List-Help" -msgstr "List-Help" - -#: lib/Horde/Mime/Headers.php:542 -msgid "List-Id" -msgstr "List-Id" - -#: lib/Horde/Mime/Headers.php:538 -msgid "List-Owner" -msgstr "List-Owner" - -#: lib/Horde/Mime/Headers.php:539 -msgid "List-Post" -msgstr "List-Post" - -#: lib/Horde/Mime/Headers.php:537 -msgid "List-Subscribe" -msgstr "List-Subscribe" - -#: lib/Horde/Mime/Headers.php:536 -msgid "List-Unsubscribe" -msgstr "List-Unsubscribe" - -#: lib/Horde/Mime/Mail.php:419 -msgid "Plaintext Version of Message" -msgstr "Versión de texto del mensaje" - -#: lib/Horde/Mime/Mdn.php:200 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Se ha mostrado el mensaje enviado el %s a %s con el asunto \"%s\".\n" -"\n" -"Ésto no garantiza que el mensaje haya sido leído o comprendido." diff --git a/lib/horde/locale/et/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/et/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 2efb015d3db..00000000000 Binary files a/lib/horde/locale/et/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/et/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/et/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 953ec0582b0..00000000000 --- a/lib/horde/locale/et/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Estonian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2011-02-02 16:17+0100\n" -"PO-Revision-Date: 2010-11-09 01:27+0200\n" -"Last-Translator: Alar Sing \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Ei Leitud" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Juurdepääs keelatud" diff --git a/lib/horde/locale/et/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/et/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index a5f121999fb..00000000000 Binary files a/lib/horde/locale/et/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/et/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/et/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 0aea058d485..00000000000 --- a/lib/horde/locale/et/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,73 +0,0 @@ -# Estonian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Disposition Notification" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "Kirja HTML variant" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Lubamatu märk e-posti aadressis: %s." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "List-Archive" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "List-Help" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "List-Id" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "List-Owner" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "List-Post" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "List-Subscribe" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "List-Unsubscribe" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "Kirja tekstikuju" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Kiri mis saadeti %s aadressile %s teemaga \"%s\" on avatud.\n" -"\n" -"See ei garanteeri et kiri läbi loeti või sellest aru saadi." diff --git a/lib/horde/locale/eu/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/eu/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 2fc67250fda..00000000000 Binary files a/lib/horde/locale/eu/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/eu/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/eu/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 0c09e9c8c4e..00000000000 --- a/lib/horde/locale/eu/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,27 +0,0 @@ -# Basque translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-01-17 12:38+0100\n" -"PO-Revision-Date: 2013-01-16 10:17+0100\n" -"Last-Translator: Ibon Igartua \n" -"Language-Team: Euskal Herriko Unibertsitatea \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-Language: Basque\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Ez da aurkitu" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Baimena ukatu da" diff --git a/lib/horde/locale/eu/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/eu/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index 80367e62b42..00000000000 Binary files a/lib/horde/locale/eu/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/eu/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/eu/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index 9f2880e387b..00000000000 --- a/lib/horde/locale/eu/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,198 +0,0 @@ -# Basque translations for Horde_Imap_Client package. -# Copyright 2012-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# Automatically generated, 2012. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-11-06 16:40+0100\n" -"PO-Revision-Date: 2013-01-16 10:32+0100\n" -"Last-Translator: Ibon Igartua \n" -"Language-Team: Euskal Herriko Unibertsitatea \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-Language: Basque\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:25 -#, fuzzy, php-format -msgid "%s not supported on POP3 servers." -msgstr "ACL ez dago konfiguratuta zerbitzari honetarako." - -#: lib/Horde/Imap/Client/Socket.php:4364 -msgid "Authentication failed." -msgstr "Autentifikazioak huts egin du." - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:149 -msgid "Authentication failure." -msgstr "Huts egitea autentifikazioan." - -#: lib/Horde/Imap/Client/Socket.php:931 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "Ezin izan da ireki \"%s\" postontzia." - -#: lib/Horde/Imap/Client/Socket.php:335 -#, fuzzy -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "Ezin izan da PGP gako-zerbitzari publikora konektatu" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:189 -#: lib/Horde/Imap/Client/Socket/Pop3.php:201 -#, fuzzy -msgid "Could not open secure connection to the POP3 server." -msgstr "Ezin izan da PGP gako-zerbitzari publikora konektatu" - -#: lib/Horde/Imap/Client/Socket.php:4265 -msgid "Could not save message data because it is too large." -msgstr "Ezin izan dira gorde mezuaren datuak, handiegia delako." - -#: lib/Horde/Imap/Client/Socket.php:4256 -#, fuzzy -msgid "Could not save message on server." -msgstr "Ezin izan da mezu-daturik eskuratu posta-zerbitzaritik." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:280 -msgid "Error connecting to POP3 server." -msgstr "Errorea POP3 zerbitzariarekin konektatzean." - -#: lib/Horde/Imap/Client/Socket.php:504 -msgid "Error connecting to mail server." -msgstr "Errorea posta-zerbitzariarekin konektatzean." - -#: lib/Horde/Imap/Client/Socket.php:3683 lib/Horde/Imap/Client/Socket.php:3964 -msgid "Error when communicating with the mail server." -msgstr "Errorea posta-zerbitzariarekin komunikatzean." - -#: lib/Horde/Imap/Client/Socket.php:3823 lib/Horde/Imap/Client/Socket.php:3854 -msgid "IMAP error reported by server." -msgstr "Zerbitzariak IMAP errorea eman du." - -#: lib/Horde/Imap/Client/Socket.php:3389 -#, fuzzy, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "Sarrera ez da baliozkoa" - -#: lib/Horde/Imap/Client/Socket.php:395 -#, fuzzy -msgid "Mail server denied authentication." -msgstr "Erabiltzailea ez dago autentifikatuta." - -#: lib/Horde/Imap/Client/Socket.php:1812 lib/Horde/Imap/Client/Socket.php:2483 -#: lib/Horde/Imap/Client/Socket.php:2504 lib/Horde/Imap/Client/Socket.php:2933 -#: lib/Horde/Imap/Client/Socket.php:2988 -#, fuzzy -msgid "Mailbox does not support mod-sequences." -msgstr "Ez dago %s postontzirik." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1156 -msgid "POP3 error reported by server." -msgstr "Zerbitzariak POP3 errorea eman du." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:240 -#, fuzzy -msgid "POP3 server denied authentication." -msgstr "Erabiltzailea ez dago autentifikatuta." - -#: lib/Horde/Imap/Client/Socket.php:4356 -#, fuzzy -msgid "Remote server is temporarily unavailable." -msgstr "Urruneko zerbitzaria erorita dago. Saiatu berriro geroago." - -#: lib/Horde/Imap/Client/Socket.php:323 -#, fuzzy -msgid "Server does not support TLS connections." -msgstr "Zerbitzariak ez du onartzen ACLrik." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:189 -#, fuzzy -msgid "Server does not support secure connections." -msgstr "Zerbitzariak ez du onartzen ACLrik." - -#: lib/Horde/Imap/Client/Socket.php:536 -#, fuzzy -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "Zerbitzariak ez du onartzen ACLrik." - -#: lib/Horde/Imap/Client/Socket.php:4435 -#, fuzzy -msgid "The mail server has denied the request." -msgstr "" -"Posta-zerbitzariak eskaera ukatu du. Errorearen xehetasunak erregistratu " -"dira administratzailearentzat." - -#: lib/Horde/Imap/Client/Socket.php:4419 -#, fuzzy -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "" -"Zure postontzian hondatutako datuak daudela jakinarazi du posta-" -"zerbitzariak. Errorearen xehetasunak erregistratu dira " -"administratzailearentzat." - -#: lib/Horde/Imap/Client/Socket.php:4177 lib/Horde/Imap/Client/Socket.php:4222 -#, fuzzy -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "Zerbitzariak ezin izan du mezu-zerrenda sortu." - -#: lib/Horde/Imap/Client/Socket.php:4327 -#, fuzzy -msgid "The metadata item could not be saved because it is too large." -msgstr "Mezu-zati hau ezin da bistaratu, handiegia delako." - -#: lib/Horde/Imap/Client/Socket.php:4336 -#, fuzzy -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "Ezin izan da objektua ezabatu, lehendik ez dagoelako." - -#: lib/Horde/Imap/Client/Socket.php:4453 -msgid "The object could not be created because it already exists." -msgstr "Ezin izan da objektua sortu, lehendik badagoelako." - -#: lib/Horde/Imap/Client/Socket.php:4462 -msgid "The object could not be deleted because it does not exist." -msgstr "Ezin izan da objektua ezabatu, lehendik ez dagoelako." - -#: lib/Horde/Imap/Client/Socket.php:4444 -#, fuzzy -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "Huts egin du eragiketak, posta-zerbitzariko kuota gainditu duzulako." - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:36 -#, fuzzy, php-format -msgid "The server does not support the %s extension." -msgstr "Arakatzaileak ez du eginbide hori onartzen." - -#: lib/Horde/Imap/Client/Socket.php:4471 -#, fuzzy -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "Fitxategi-formatu hau ez da onartzen." - -#: lib/Horde/Imap/Client/Socket.php:4405 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "" -"Uneko arazoren bat gertatu da eragiketa hau egitean. Saiatu berriro geroago." - -#: lib/Horde/Imap/Client/Socket.php:604 -#: lib/Horde/Imap/Client/Socket/Pop3.php:334 -#, fuzzy -msgid "Unexpected response from server when authenticating." -msgstr "Ustekabeko erantzuna urruneko zerbitzaritik." - -#: lib/Horde/Imap/Client/Socket.php:648 -#: lib/Horde/Imap/Client/Socket/Pop3.php:374 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "Autentifikazio metodo ezezaguna: %s" - -#: lib/Horde/Imap/Client/Socket.php:4396 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "Ez daukazu eragiketa hau egiteko behar den baimenik." diff --git a/lib/horde/locale/eu/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/eu/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 301bfea55fb..00000000000 Binary files a/lib/horde/locale/eu/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/eu/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/eu/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index aa65467110d..00000000000 --- a/lib/horde/locale/eu/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,71 +0,0 @@ -# Basque translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-08-29 13:30+0200\n" -"PO-Revision-Date: 2013-01-16 13:49+0100\n" -"Last-Translator: Ibon Igartua \n" -"Language-Team: Euskal Herriko Unibertsitatea \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Poedit-Language: Basque\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "Hartu-agiria" - -#: lib/Horde/Mime/Mail.php:419 -msgid "HTML Version of Message" -msgstr "Mezuaren HTML bertsioa" - -#: lib/Horde/Mime/Headers.php:540 -msgid "List-Archive" -msgstr "List-Archive" - -#: lib/Horde/Mime/Headers.php:535 -msgid "List-Help" -msgstr "List-Help" - -#: lib/Horde/Mime/Headers.php:542 -msgid "List-Id" -msgstr "List-Id" - -#: lib/Horde/Mime/Headers.php:538 -msgid "List-Owner" -msgstr "List-Owner" - -#: lib/Horde/Mime/Headers.php:539 -msgid "List-Post" -msgstr "List-Post" - -#: lib/Horde/Mime/Headers.php:537 -msgid "List-Subscribe" -msgstr "List-Subscribe" - -#: lib/Horde/Mime/Headers.php:536 -msgid "List-Unsubscribe" -msgstr "List-Unsubscribe" - -#: lib/Horde/Mime/Mail.php:417 -msgid "Plaintext Version of Message" -msgstr "Mezuaren testu soileko bertsioa" - -#: lib/Horde/Mime/Mdn.php:200 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Data: %s, Nori zuzendua: %s eta Gaia: \"%s\" duen mezua bistaratuta izan " -"da.\n" -"\n" -"Horrek ez du esan nahi hartzaileak mezua irakurri edo ulertu egin duenik." diff --git a/lib/horde/locale/fa/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/fa/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 71938c4918c..00000000000 Binary files a/lib/horde/locale/fa/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/fa/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/fa/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 7d3d55b0227..00000000000 --- a/lib/horde/locale/fa/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Persian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "%s پیدا نشد" - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "مجوز" diff --git a/lib/horde/locale/fa/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/fa/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index ce338baf89d..00000000000 Binary files a/lib/horde/locale/fa/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/fa/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/fa/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index cccd73cd294..00000000000 --- a/lib/horde/locale/fa/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,71 +0,0 @@ -# Persian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "حالت تذکر" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "آدرس مقصد نامعتبر" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "فهرست آرشیو" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "فهرست راهنما" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "فهرست Id" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "فهرست مالک" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "فهرست پستی" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "فهرست عضویّت" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "فهرست عدم عضویّت" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, fuzzy, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"پیغام فرستاده شده روی %s به %s با موضوع \"%s\" نمایش داده شده است.\n" -"تضمینی برای خوانده شدن و یا درک آن وجود ندارد" diff --git a/lib/horde/locale/fi/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/fi/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 9467d0b696d..00000000000 Binary files a/lib/horde/locale/fi/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/fi/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/fi/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index f2f3ae3b87e..00000000000 --- a/lib/horde/locale/fi/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Finnish translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Leena Heino , 2010-2012. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2011-02-02 16:17+0100\n" -"PO-Revision-Date: 2012-03-07 15:05:44+0200\n" -"Last-Translator: Leena Heino \n" -"Language-Team: Finnish \n" -"Language: fi\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Ei löytynyt" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Käyttö kielletty" diff --git a/lib/horde/locale/fi/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/fi/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index 543966c87cd..00000000000 Binary files a/lib/horde/locale/fi/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/fi/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/fi/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index ef1f8bd0a99..00000000000 --- a/lib/horde/locale/fi/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,259 +0,0 @@ -# Finnish translations for Horde_Imap_Client package. -# Copyright 2012-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# Leena Heino , 2011-2012. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client \n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-11-06 16:40+0100\n" -"PO-Revision-Date: 2012-11-07 17:24:08+0200\n" -"Last-Translator: Leena Heino \n" -"Language-Team: Finnish \n" -"Language: fi\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:25 -#, php-format -msgid "%s not supported on POP3 servers." -msgstr "%s ei ole tuettu POP3-palvelimille." - -#: lib/Horde/Imap/Client/Socket.php:4380 -msgid "Authentication credentials have expired." -msgstr "Autentikointitiedot ovat vanhentuneet." - -#: lib/Horde/Imap/Client/Socket.php:4364 -msgid "Authentication failed." -msgstr "Autentikointi epäonnistui." - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:149 -msgid "Authentication failure." -msgstr "Autentikointivirhe." - -#: lib/Horde/Imap/Client/Socket.php:4372 -msgid "Authentication was successful, but authorization failed." -msgstr "Autentikointi epäonnistui, mutta autorisointi epäonnistui." - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:34 -msgid "Bad tagged response." -msgstr "Virheellinen tagätty vastaus." - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:36 -msgid "Cannot convert search query text to new charset" -msgstr "Ei voida muuntaa hakulauseen tekstiä uuteen merkistöön" - -#: lib/Horde/Imap/Client/Base.php:1899 lib/Horde/Imap/Client/Base.php:1958 -msgid "Cannot expunge read-only mailbox." -msgstr "" -"Ei voida tyhjentää poistetuja vain lukuun tarkoitetusta postilaatikosta." - -#: lib/Horde/Imap/Client/Socket.php:4165 -msgid "Charset used in search query is not supported on the mail server." -msgstr "Palvelin ei tue haussa käytettyä merkistöä." - -#: lib/Horde/Imap/Client/Socket.php:931 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "Ei voitu aukaista postilaatikkoa \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:335 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "Ei voitu aukaista salattua TLS-yhteyttä IMAP-palvelimelle." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:189 -#: lib/Horde/Imap/Client/Socket/Pop3.php:201 -msgid "Could not open secure connection to the POP3 server." -msgstr "Ei voitu aukaista salattua yhteyttä POP3-palvelimelle" - -#: lib/Horde/Imap/Client/Socket.php:4265 -msgid "Could not save message data because it is too large." -msgstr "Liian suuren tietomäärän takia viestin tietoja ei voitu talentaa." - -#: lib/Horde/Imap/Client/Socket.php:4256 -msgid "Could not save message on server." -msgstr "Viestiä ei voi tallentaa palvelimelle." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:280 -msgid "Error connecting to POP3 server." -msgstr "Virhetilanne yhdistettäessä POP3-palvelimelle." - -#: lib/Horde/Imap/Client/Socket.php:504 -msgid "Error connecting to mail server." -msgstr "Virhetilanne yhdistettäessä postipalvelimelle." - -#: lib/Horde/Imap/Client/Utf7imap.php:117 -#: lib/Horde/Imap/Client/Utf7imap.php:142 -#: lib/Horde/Imap/Client/Utf7imap.php:146 -#: lib/Horde/Imap/Client/Utf7imap.php:205 -#: lib/Horde/Imap/Client/Utf7imap.php:222 -#: lib/Horde/Imap/Client/Utf7imap.php:226 -#: lib/Horde/Imap/Client/Utf7imap.php:234 -#: lib/Horde/Imap/Client/Utf7imap.php:240 -msgid "Error converting UTF7-IMAP string." -msgstr "Virhetilanne muunnettaessa UTF7-IMAP merkkijonoa." - -#: lib/Horde/Imap/Client/Socket.php:3683 lib/Horde/Imap/Client/Socket.php:3964 -msgid "Error when communicating with the mail server." -msgstr "Virhetilanne liikennöinnissä postipalvelimelle. " - -#: lib/Horde/Imap/Client/Socket.php:3838 -msgid "IMAP Server closed the connection." -msgstr "IMAP-palvelin sulki yhteyden." - -#: lib/Horde/Imap/Client/Socket.php:3823 lib/Horde/Imap/Client/Socket.php:3854 -msgid "IMAP error reported by server." -msgstr "IMAP-palvelimen antama virhe." - -#: lib/Horde/Imap/Client/Socket.php:3389 -#, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "Epäkelpo METADATA tieto: \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:3476 -#, php-format -msgid "Invalid METADATA value type \"%s\"." -msgstr "Epäkelpo METADATA arvotyyppi: \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:3890 -msgid "Mail server closed the connection unexpectedly." -msgstr "Postipalvelin sulki yhteyden odottamatta." - -#: lib/Horde/Imap/Client/Socket.php:395 -msgid "Mail server denied authentication." -msgstr "Postipalvelin esti autentikoinnin." - -#: lib/Horde/Imap/Client/Socket.php:1812 lib/Horde/Imap/Client/Socket.php:2483 -#: lib/Horde/Imap/Client/Socket.php:2504 lib/Horde/Imap/Client/Socket.php:2933 -#: lib/Horde/Imap/Client/Socket.php:2988 -msgid "Mailbox does not support mod-sequences." -msgstr "Postilaatikko ei tue mod-sequences -piirrettä." - -#: lib/Horde/Imap/Client/Socket.php:378 -msgid "No supported IMAP authentication method could be found." -msgstr "Tuettua IMAP-autentikointitapaa ei löytynyt." - -#: lib/Horde/Imap/Client/Socket.php:4388 -msgid "Operation failed due to a lack of a secure connection." -msgstr "Toiminto epäonnistui salatut yhteydet eivät ole käytettävissä." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1096 -msgid "POP3 Server closed the connection unexpectedly." -msgstr "POP3-palvelin katkaisi yhteyden yllättäen." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1156 -msgid "POP3 error reported by server." -msgstr "POP3-palvelimen antama virhe." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:240 -msgid "POP3 server denied authentication." -msgstr "POP3-palvelin esti autentikoinnin." - -#: lib/Horde/Imap/Client/Socket.php:4356 -msgid "Remote server is temporarily unavailable." -msgstr "Etäpalvelin on väliakaisesti saavuttamattomissa." - -#: lib/Horde/Imap/Client/Socket.php:323 -msgid "Server does not support TLS connections." -msgstr "Palvelin ei tue TLS-yhteyksiä." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:189 -msgid "Server does not support secure connections." -msgstr "Palvelin ei tue salattuja yhteyksiä." - -#: lib/Horde/Imap/Client/Socket.php:527 -msgid "Server rejected connection." -msgstr "Palvelin hylkäsi yhteyden." - -#: lib/Horde/Imap/Client/Socket.php:3748 -msgid "Server write error." -msgstr "Palvelimen kirjoitusvirhe." - -#: lib/Horde/Imap/Client/Socket.php:4309 -msgid "The comparison algorithm was not recognized by the server." -msgstr "Palvelin ei tunnista vertailualgoritmiä." - -#: lib/Horde/Imap/Client/Socket.php:536 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "Postipalvelin ei tue toimintoa IMAP4rev1 (RFC 3501)." - -#: lib/Horde/Imap/Client/Socket.php:4435 -msgid "The mail server has denied the request." -msgstr "Postipalvelin esti pyynnön." - -#: lib/Horde/Imap/Client/Socket.php:4419 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "" -"Postipalvelin raportoi, että postilaatikossa on korruptoituneita tietoja." - -#: lib/Horde/Imap/Client/Socket.php:4177 lib/Horde/Imap/Client/Socket.php:4222 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "Postipalvelin ei pystynyt käsittelemään viestin tietoja." - -#: lib/Horde/Imap/Client/Socket.php:4327 -msgid "The metadata item could not be saved because it is too large." -msgstr "Metadata tietoja ei voitu tallentaa, koska se oli liian suuri." - -#: lib/Horde/Imap/Client/Socket.php:4345 -msgid "" -"The metadata item could not be saved because the maximum number of " -"annotations has been exceeded." -msgstr "" -"Metadata tietoa ei voi tallentaa, koska lisätietojen suurin sallittu määrä " -"on ylittynyt." - -#: lib/Horde/Imap/Client/Socket.php:4336 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "" -"Metadata tietoja ei voitu tallentaa, koska palvelin ei tue yksilökohtaisten " -"lisätietojen tallennusta." - -#: lib/Horde/Imap/Client/Socket.php:4453 -msgid "The object could not be created because it already exists." -msgstr "Objektia ei voitu luoda, koska se on jo olemassa." - -#: lib/Horde/Imap/Client/Socket.php:4462 -msgid "The object could not be deleted because it does not exist." -msgstr "Objektia ei voitu poistaa, koska sitä ei ole olemassa." - -#: lib/Horde/Imap/Client/Socket.php:4444 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "Operaatio epäonnistui, koska kiintiö on ylittynyt postipalvelimella." - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:36 -#, php-format -msgid "The server does not support the %s extension." -msgstr "Palvelin ei tue laajennusta %s." - -#: lib/Horde/Imap/Client/Socket.php:4471 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "Postilaatikon erikoiskäyttö atribuutti ei ole tuettu." - -#: lib/Horde/Imap/Client/Socket.php:4405 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "" -"Väliaikainen ongelmatilanne yritettäessä tätä operaatiota. Yritä myöhemmin " -"uudestaan." - -#: lib/Horde/Imap/Client/Socket.php:604 -#: lib/Horde/Imap/Client/Socket/Pop3.php:334 -msgid "Unexpected response from server when authenticating." -msgstr "Odottamaton vastaus palvelimelta autentikoinnin aikana." - -#: lib/Horde/Imap/Client/Socket.php:648 -#: lib/Horde/Imap/Client/Socket/Pop3.php:374 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "Tuntematon autentikointimetori: %s" - -#: lib/Horde/Imap/Client/Socket.php:4396 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "Sinulla ei ole riittäviä oikeuksia tämän toiminnon suorittamiseen." diff --git a/lib/horde/locale/fi/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/fi/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index ea195e89ae6..00000000000 Binary files a/lib/horde/locale/fi/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/fi/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/fi/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 3ec1d308353..00000000000 --- a/lib/horde/locale/fi/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,69 +0,0 @@ -# Finnish translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Leena Heino , 2010-2012. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-08-29 13:30+0200\n" -"PO-Revision-Date: 2012-03-07 15:08:44+0200\n" -"Last-Translator: Leena Heino \n" -"Language-Team: Finnish \n" -"Language: fi\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "Perillemenoilmoitus" - -#: lib/Horde/Mime/Mail.php:419 -msgid "HTML Version of Message" -msgstr "Viestin HTML-versio" - -#: lib/Horde/Mime/Headers.php:540 -msgid "List-Archive" -msgstr "Lista-Arkisto" - -#: lib/Horde/Mime/Headers.php:535 -msgid "List-Help" -msgstr "Lista-Ohje" - -#: lib/Horde/Mime/Headers.php:542 -msgid "List-Id" -msgstr "Lista-Id" - -#: lib/Horde/Mime/Headers.php:538 -msgid "List-Owner" -msgstr "Lista-Omistaja" - -#: lib/Horde/Mime/Headers.php:539 -msgid "List-Post" -msgstr "Lista-Viesti" - -#: lib/Horde/Mime/Headers.php:537 -msgid "List-Subscribe" -msgstr "Lista-Tilaus" - -#: lib/Horde/Mime/Headers.php:536 -msgid "List-Unsubscribe" -msgstr "Lista-Tilauksen-lopettaminen" - -#: lib/Horde/Mime/Mail.php:417 -msgid "Plaintext Version of Message" -msgstr "Viestin tekstiversio." - -#: lib/Horde/Mime/Mdn.php:200 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Viesti lähetetty %s vastaanottajalle %s otsikkona \"%s\" on näytetty " -"hänelle.\n" -"Tämä ei tarkoita sitä, että viestiä olisi luettu tai ymmärretty." diff --git a/lib/horde/locale/fr/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/fr/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index a9766164662..00000000000 Binary files a/lib/horde/locale/fr/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/fr/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/fr/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 598c8d088e5..00000000000 --- a/lib/horde/locale/fr/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,28 +0,0 @@ -# French translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# Paul De Vlieger , 2013 -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception \n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-01-17 12:38+0100\n" -"PO-Revision-Date: 2013-01-14 11:54+0100\n" -"Last-Translator: Paul De Vlieger \n" -"Language-Team: French \n" -"Language: fr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Lokalize 1.4\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Non trouvé" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Autorisation rejetée" diff --git a/lib/horde/locale/fr/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/fr/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index b5db9930758..00000000000 Binary files a/lib/horde/locale/fr/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/fr/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/fr/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index 63db8e06132..00000000000 --- a/lib/horde/locale/fr/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,272 +0,0 @@ -# French translations for Horde_Imap_Client package. -# Copyright (C) 2013 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# -# Paul De Vlieger , 2013 -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client \n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2013-01-14 09:19+0100\n" -"PO-Revision-Date: 2013-01-16 16:26+0100\n" -"Last-Translator: Paul De Vlieger \n" -"Language-Team: French \n" -"Language: fr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Lokalize 1.4\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:33 -#, php-format -msgid "%s not supported on POP3 servers." -msgstr "%s n'est pas supporté sur les serveurs POP3." - -#: lib/Horde/Imap/Client/Socket.php:4419 -msgid "Authentication credentials have expired." -msgstr "Votre session a expiré." - -#: lib/Horde/Imap/Client/Socket.php:4403 -msgid "Authentication failed." -msgstr "La connexion a échouée." - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:157 -msgid "Authentication failure." -msgstr "Échec de la connexion." - -#: lib/Horde/Imap/Client/Socket.php:4411 -msgid "Authentication was successful, but authorization failed." -msgstr "L'authentification a réussi mais pas l'autorisation." - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:42 -msgid "Bad tagged response." -msgstr "Mauvaise réponse." - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:44 -msgid "Cannot convert search query text to new charset" -msgstr "" -"Impossible de convertir la recherche dans le nouveau jeu de caractères." - -#: lib/Horde/Imap/Client/Base.php:1900 lib/Horde/Imap/Client/Base.php:1959 -msgid "Cannot expunge read-only mailbox." -msgstr "Impossible d'effacer une boite mail en lecture seule." - -#: lib/Horde/Imap/Client/Socket.php:4198 -msgid "Charset used in search query is not supported on the mail server." -msgstr "" -"Le jeu de caractères utilisé dans la recherche n'est pas reconnu sur le " -"serveur de messagerie." - -#: lib/Horde/Imap/Client/Socket.php:950 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "Impossible d'ouvrir la boite mail « %s »." - -#: lib/Horde/Imap/Client/Socket.php:357 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "Échec de la connexion sécurisée TLS au serveur IMAP." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:200 -#: lib/Horde/Imap/Client/Socket/Pop3.php:212 -msgid "Could not open secure connection to the POP3 server." -msgstr "Échec de la connexion sécurisée TLS au serveur POP3." - -#: lib/Horde/Imap/Client/Socket.php:4304 -msgid "Could not save message data because it is too large." -msgstr "Le message est trop grand pour être sauvegardé." - -#: lib/Horde/Imap/Client/Socket.php:4295 -msgid "Could not save message on server." -msgstr "Impossible de sauvegarder le message sur le serveur." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:291 -msgid "Error connecting to POP3 server." -msgstr "Échec de la connexion au serveur POP3." - -#: lib/Horde/Imap/Client/Socket.php:526 -msgid "Error connecting to mail server." -msgstr "Échec de la connexion au serveur de messagerie." - -#: lib/Horde/Imap/Client/Utf7imap.php:127 -#: lib/Horde/Imap/Client/Utf7imap.php:152 -#: lib/Horde/Imap/Client/Utf7imap.php:156 -#: lib/Horde/Imap/Client/Utf7imap.php:215 -#: lib/Horde/Imap/Client/Utf7imap.php:232 -#: lib/Horde/Imap/Client/Utf7imap.php:236 -#: lib/Horde/Imap/Client/Utf7imap.php:244 -#: lib/Horde/Imap/Client/Utf7imap.php:250 -msgid "Error converting UTF7-IMAP string." -msgstr "Erreur lors de la conversion UTF7-IMAP." - -#: lib/Horde/Imap/Client/Socket.php:3736 lib/Horde/Imap/Client/Socket.php:4012 -msgid "Error when communicating with the mail server." -msgstr "Erreur de communication avec le serveur de messagerie." - -#: lib/Horde/Imap/Client/Socket.php:3891 -msgid "IMAP Server closed the connection." -msgstr "Le serveur IMAP a fermé la connexion." - -#: lib/Horde/Imap/Client/Socket.php:3876 lib/Horde/Imap/Client/Socket.php:3907 -msgid "IMAP error reported by server." -msgstr "Erreur IMAP sur le serveur." - -#: lib/Horde/Imap/Client/Socket.php:3460 -#, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "Entrée METADATA invalide: « %s »" - -#: lib/Horde/Imap/Client/Socket.php:3545 -#, php-format -msgid "Invalid METADATA value type \"%s\"." -msgstr "Valeur METADATA invalide: « %s »" - -#: lib/Horde/Imap/Client/Socket.php:3943 -msgid "Mail server closed the connection unexpectedly." -msgstr "Le serveur de messagerie a fermé la connexion de façon inattendue." - -#: lib/Horde/Imap/Client/Socket.php:417 -msgid "Mail server denied authentication." -msgstr "Le serveur mail a refusé l'authentification." - -#: lib/Horde/Imap/Client/Socket.php:1867 lib/Horde/Imap/Client/Socket.php:2536 -#: lib/Horde/Imap/Client/Socket.php:2557 lib/Horde/Imap/Client/Socket.php:3001 -#: lib/Horde/Imap/Client/Socket.php:3057 -msgid "Mailbox does not support mod-sequences." -msgstr "Les boites mail ne supportent pas les mod-sequences." - -#: lib/Horde/Imap/Client/Socket.php:400 -msgid "No supported IMAP authentication method could be found." -msgstr "Aucune méthode d'authentification IMAP n'a pu être trouvée." - -#: lib/Horde/Imap/Client/Socket.php:4427 -msgid "Operation failed due to a lack of a secure connection." -msgstr "L'opération a échouée : connexion sécurisée manquante." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1107 -msgid "POP3 Server closed the connection unexpectedly." -msgstr "Le serveur POP3 a fermé la connexion de façon inattendue." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1175 -msgid "POP3 error reported by server." -msgstr "Erreur POP3 sur le serveur." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:251 -msgid "POP3 server denied authentication." -msgstr "Le serveur a refusé l'authentification." - -#: lib/Horde/Imap/Client/Socket.php:4395 -msgid "Remote server is temporarily unavailable." -msgstr "Le serveur distant est temporairement indisponible." - -#: lib/Horde/Imap/Client/Socket.php:345 -msgid "Server does not support TLS connections." -msgstr "Le serveur ne supporte pas les connexions TLS." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:200 -msgid "Server does not support secure connections." -msgstr "Le serveur ne supporte pas les connexions sécurisées." - -#: lib/Horde/Imap/Client/Socket.php:549 -msgid "Server rejected connection." -msgstr "Le serveur a rejeté la connexion." - -#: lib/Horde/Imap/Client/Socket.php:3801 -msgid "Server write error." -msgstr "Erreur d'écriture sur le serveur." - -#: lib/Horde/Imap/Client/Socket.php:4348 -msgid "The comparison algorithm was not recognized by the server." -msgstr "L'algorithme de comparaison n'a pas été reconnu par le serveur." - -#: lib/Horde/Imap/Client/Socket.php:558 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "Le serveur de messagerie ne supporte pas IMAP4rev1 (RFC 3501)." - -#: lib/Horde/Imap/Client/Socket.php:4474 -msgid "The mail server has denied the request." -msgstr "Le serveur de messagerie a refusé la requête." - -#: lib/Horde/Imap/Client/Socket.php:4458 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "" -"Le serveur de messagerie signale une corruption de données dans votre boite " -"mail." - -#: lib/Horde/Imap/Client/Socket.php:4261 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "" -"Le serveur de messagerie n'a pas réussi à récupérer le contenu des messages." - -#: lib/Horde/Imap/Client/Socket.php:4214 -#, php-format -msgid "" -"The mail server was unable to parse the contents of the mail message: %s" -msgstr "" -"Le serveur de messagerie n'a pas réussi à récupérer le contenu du message: %s" - -#: lib/Horde/Imap/Client/Socket.php:4366 -msgid "The metadata item could not be saved because it is too large." -msgstr "Les méta-données sont trop grandes pour être sauvegardées." - -#: lib/Horde/Imap/Client/Socket.php:4384 -msgid "" -"The metadata item could not be saved because the maximum number of " -"annotations has been exceeded." -msgstr "" -"La méta-donnée n'a pas pu être enregistrée car le maximum d'annotations a " -"été dépassé." - -#: lib/Horde/Imap/Client/Socket.php:4375 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "" -"La méta-donnée n'a pas pu être enregistrée car le serveur ne supporte pas " -"les annotations privées." - -#: lib/Horde/Imap/Client/Socket.php:4492 -msgid "The object could not be created because it already exists." -msgstr "L'objet ne peut être crée car il existe déjà." - -#: lib/Horde/Imap/Client/Socket.php:4501 -msgid "The object could not be deleted because it does not exist." -msgstr "L'objet ne peut être supprimé car il n'existe pas." - -#: lib/Horde/Imap/Client/Socket.php:4483 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "L'opération a échouée car le quota a été dépassé sur ce serveur." - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:44 -#, php-format -msgid "The server does not support the %s extension." -msgstr "Le serveur ne supporte pas l'extension: %s." - -#: lib/Horde/Imap/Client/Socket.php:4510 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "L'attribut spécial demandé pour la boite mail n'est pas supporté." - -#: lib/Horde/Imap/Client/Socket.php:4444 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "" -"Il y a eu une erreur temporaire en essayant d'effectuer cette action. " -"Veuillez réessayer plus tard." - -#: lib/Horde/Imap/Client/Socket.php:626 -#: lib/Horde/Imap/Client/Socket/Pop3.php:345 -msgid "Unexpected response from server when authenticating." -msgstr "Réponse inattendue du serveur distant lors de l'authentification." - -#: lib/Horde/Imap/Client/Socket.php:670 -#: lib/Horde/Imap/Client/Socket/Pop3.php:385 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "La méthode d'authentification %s est inconnue." - -#: lib/Horde/Imap/Client/Socket.php:4435 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "Vous n'avez pas l'autorisation d'effectuer cette opération." diff --git a/lib/horde/locale/fr/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/fr/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 94cc0c72ddc..00000000000 Binary files a/lib/horde/locale/fr/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/fr/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/fr/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index f719660e744..00000000000 --- a/lib/horde/locale/fr/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,72 +0,0 @@ -# French translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Avis de livraison" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "Version HTML du message" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Caractère invalide dans l'adresse de messagerie : %s." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "Archives de la liste" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "Aide de la liste" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "Id. de la liste" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "Propriétaire de la liste" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "Envoi à la liste" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "Abonnement à la liste" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "Désabonnement de la liste" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "Version texte brut du message" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Le message envoyé le %s à %s avec comme sujet « %s » a été affiché.\n" -"Il n'y a aucune garantie que ce message ait été lu ou compris." diff --git a/lib/horde/locale/gl/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/gl/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 71938c4918c..00000000000 Binary files a/lib/horde/locale/gl/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/gl/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/gl/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 9a9f7b3de67..00000000000 --- a/lib/horde/locale/gl/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,24 +0,0 @@ -# Galician translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "" diff --git a/lib/horde/locale/gl/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/gl/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index e615918c106..00000000000 Binary files a/lib/horde/locale/gl/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/gl/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/gl/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 3bc8bb55f71..00000000000 --- a/lib/horde/locale/gl/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,70 +0,0 @@ -# Galician translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Listar os temas de axuda" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/he/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/he/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index b8d6164080f..00000000000 Binary files a/lib/horde/locale/he/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/he/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/he/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index fe1fa525f25..00000000000 --- a/lib/horde/locale/he/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,25 +0,0 @@ -# Hebrew translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "" diff --git a/lib/horde/locale/he/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/he/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 427504f5af3..00000000000 Binary files a/lib/horde/locale/he/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/he/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/he/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index bd361533149..00000000000 --- a/lib/horde/locale/he/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,71 +0,0 @@ -# Hebrew translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "עזרה" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/hr/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/hr/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 5339aa0eb4d..00000000000 Binary files a/lib/horde/locale/hr/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/hr/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/hr/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 6e79e7e8f97..00000000000 --- a/lib/horde/locale/hr/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,27 +0,0 @@ -# Croatian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Valentin Vidic , 2011. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2011-02-02 16:17+0100\n" -"PO-Revision-Date: 2011-11-08 16:49+0200\n" -"Last-Translator: Valentin Vidic \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: hr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Nije pronađeno" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Pristup odbijen" diff --git a/lib/horde/locale/hr/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/hr/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index ae80fefaeda..00000000000 Binary files a/lib/horde/locale/hr/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/hr/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/hr/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 8685b18f940..00000000000 --- a/lib/horde/locale/hr/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,78 +0,0 @@ -# Croatian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Valentin Vidic , 2011. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2011-11-04 15:10+0100\n" -"PO-Revision-Date: 2011-11-08 16:49+0200\n" -"Last-Translator: Valentin Vidic \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: hr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: lib/Horde/Mime/Mdn.php:191 -msgid "Disposition Notification" -msgstr "Obavijest o raspoloživosti" - -#: lib/Horde/Mime/Mail.php:457 -msgid "HTML Version of Message" -msgstr "HTML verzija poruke" - -#: lib/Horde/Mime/Mail.php:401 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Neispravan znak u e-mail adresi: %s." - -#: lib/Horde/Mime/Headers.php:534 -msgid "List-Archive" -msgstr "Lista-Arhiva" - -#: lib/Horde/Mime/Headers.php:529 -msgid "List-Help" -msgstr "Lista-Pomoć" - -#: lib/Horde/Mime/Headers.php:536 -msgid "List-Id" -msgstr "ID liste" - -# vlasnik? -#: lib/Horde/Mime/Headers.php:532 -msgid "List-Owner" -msgstr "Vlasnik liste" - -# Lista - Šalji -#: lib/Horde/Mime/Headers.php:533 -msgid "List-Post" -msgstr "Pošiljanje na listu" - -# Lista - Pretplati ili Prijavi se -#: lib/Horde/Mime/Headers.php:531 -msgid "List-Subscribe" -msgstr "Pretplati se na listu" - -#: lib/Horde/Mime/Headers.php:530 -msgid "List-Unsubscribe" -msgstr "Odjavi sa liste" - -#: lib/Horde/Mime/Mail.php:455 -msgid "Plaintext Version of Message" -msgstr "Poruka kao obični tekst" - -#: lib/Horde/Mime/Mdn.php:203 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Poruka poslana %s za %s s temom \"%s\" je prikazana.\n" -"\n" -"To ne jamči da je poruka pročitana ili shvaćena." diff --git a/lib/horde/locale/hu/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/hu/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index be2e4faa81c..00000000000 Binary files a/lib/horde/locale/hu/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/hu/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/hu/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index a70e67bed14..00000000000 --- a/lib/horde/locale/hu/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,25 +0,0 @@ -# Hungarian translations for Horde_Exception module. -# Copyright 2010-2013 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception \n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-01-17 12:38+0100\n" -"PO-Revision-Date: 2014-07-14 11:35+0200\n" -"Last-Translator: Andras Galos \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: hu\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Nem található" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Hozzáférés megtagadva" diff --git a/lib/horde/locale/hu/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/hu/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index 7dd73459806..00000000000 Binary files a/lib/horde/locale/hu/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/hu/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/hu/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index 8ff97f8679f..00000000000 --- a/lib/horde/locale/hu/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,257 +0,0 @@ -# Hungarian translations for Horde_Imap_Client package. -# Copyright (C) 2014 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client \n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2014-03-07 12:17+0100\n" -"PO-Revision-Date: 2014-05-05 17:32+0200\n" -"Last-Translator: Andras Galos \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: hu\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:33 -msgid "%s not supported on POP3 servers." -msgstr "A %s nem támogatott POP3 szervereken" - -#: lib/Horde/Imap/Client/Socket.php:4622 -msgid "Authentication credentials have expired." -msgstr "Bejelentkezési adatok elavultak." - -#: lib/Horde/Imap/Client/Socket.php:4606 -msgid "Authentication failed." -msgstr "A bejelentkezés nem sikerült." - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:157 -msgid "Authentication failure." -msgstr "A bejelentkezés nem sikerült." - -#: lib/Horde/Imap/Client/Socket.php:4614 -msgid "Authentication was successful, but authorization failed." -msgstr "A bejelentkezés sikerült, de a hozzáférés meg lett tagadva." - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:42 -msgid "Bad tagged response." -msgstr "Hibás válasz." - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:44 -msgid "Cannot convert search query text to new charset" -msgstr "A keresés új karakterkészletbe konvertálása nem sikerült" - -#: lib/Horde/Imap/Client/Base.php:2032 lib/Horde/Imap/Client/Base.php:2095 -msgid "Cannot expunge read-only mailbox." -msgstr "A csak olvasható mappa tiszítása nem sikerült." - -#: lib/Horde/Imap/Client/Socket.php:4400 -msgid "Charset used in search query is not supported on the mail server." -msgstr "" -"A keresésben használt karakterkódolás nem használható a levelezőszerveren." - -#: lib/Horde/Imap/Client/Socket.php:1076 -msgid "Could not open mailbox \"%s\"." -msgstr "A \"%s\" mappa nem nyitható meg." - -#: lib/Horde/Imap/Client/Socket.php:393 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "Nem sikerült biztonságos TLS kapcsolat létrehozása az IMAP szerverhez." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:194 -#: lib/Horde/Imap/Client/Socket/Pop3.php:208 -msgid "Could not open secure connection to the POP3 server." -msgstr "Nem sikerült biztonságos TLS kapcsolat létrehozása a POP3 szerverhez." - -#: lib/Horde/Imap/Client/Socket.php:4506 -msgid "Could not save message data because it is too large." -msgstr "A levél nem jelenlíthető meg, mert túl nagy." - -#: lib/Horde/Imap/Client/Socket.php:4497 -msgid "Could not save message on server." -msgstr "A levél mentése a szerverre nem sikerült." - -#: lib/Horde/Imap/Client/Socket.php:573 -#: lib/Horde/Imap/Client/Socket/Pop3.php:284 -msgid "Error connecting to mail server." -msgstr "Nem sikerült a levelezőszerverhez kapcsolódni." - -#: lib/Horde/Imap/Client/Utf7imap.php:127 -#: lib/Horde/Imap/Client/Utf7imap.php:152 -#: lib/Horde/Imap/Client/Utf7imap.php:156 -#: lib/Horde/Imap/Client/Utf7imap.php:215 -#: lib/Horde/Imap/Client/Utf7imap.php:232 -#: lib/Horde/Imap/Client/Utf7imap.php:236 -#: lib/Horde/Imap/Client/Utf7imap.php:244 -#: lib/Horde/Imap/Client/Utf7imap.php:250 -msgid "Error converting UTF7-IMAP string." -msgstr "Az UTF7-IMAP konvertálás nem sikerült." - -#: lib/Horde/Imap/Client/Socket.php:4075 -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:70 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:179 -#: lib/Horde/Imap/Client/Socket/Pop3.php:1177 -msgid "Error when communicating with the mail server." -msgstr "Hiba történt a szerverrel való kommunikációban." - -#: lib/Horde/Imap/Client/Socket.php:4187 -msgid "IMAP Server closed the connection." -msgstr "Az IMAP szerver lezárta a kapcsolatot." - -#: lib/Horde/Imap/Client/Socket.php:4173 -msgid "IMAP error reported by server." -msgstr "IMAP hibát jelzett a szerver." - -#: lib/Horde/Imap/Client/Socket.php:3682 -msgid "Invalid METADATA entry: \"%s\"." -msgstr "Érvénytelen METADATA elem: \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:3769 -msgid "Invalid METADATA value type \"%s\"." -msgstr "Érvénytelen METADATA típus: \"%s\"." - -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:120 -msgid "Mail server closed the connection unexpectedly." -msgstr "A levelezőszerver váratlanul lezárta a kapcsolatot." - -#: lib/Horde/Imap/Client/Socket.php:541 -msgid "Mail server denied authentication." -msgstr "A levelezőszerver megtagadta a hozzáférést." - -#: lib/Horde/Imap/Client/Base.php:2365 lib/Horde/Imap/Client/Base.php:2685 -#: lib/Horde/Imap/Client/Base.php:2950 lib/Horde/Imap/Client/Base.php:3035 -msgid "Mailbox does not support mod-sequences." -msgstr "A mappa nem támogatja ezt: mod-sequences." - -#: lib/Horde/Imap/Client/Socket.php:469 -msgid "No supported IMAP authentication method could be found." -msgstr "Nem sikerült támogatott IMAP bejelentkezősi módszert találni." - -#: lib/Horde/Imap/Client/Socket.php:4630 -msgid "Operation failed due to a lack of a secure connection." -msgstr "A művelet végrehajtása biztonságos kapcsolat híján nem sikerült." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1236 -msgid "POP3 error reported by server." -msgstr "A szerver POP3 hibát jelzett" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:253 -msgid "POP3 server denied authentication." -msgstr "A POP3 szerver megtagadta a hozzáférést." - -#: lib/Horde/Imap/Client/Socket.php:4598 -msgid "Remote server is temporarily unavailable." -msgstr "A távoli szerver jelenleg nem elérhető." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:62 -msgid "Server closed the connection unexpectedly." -msgstr "A szerver váratlanul lezárta a kapcsolatot." - -#: lib/Horde/Imap/Client/Socket.php:381 -msgid "Server does not support TLS connections." -msgstr "A szerver nem támogat TLS kapcsolatot." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:194 -msgid "Server does not support secure connections." -msgstr "A szerver nem támogat biztonságos kapcsolatot." - -#: lib/Horde/Imap/Client/Socket.php:593 -msgid "Server rejected connection." -msgstr "A szerver visszautasította a kapcsolatot." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:41 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:53 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:86 -msgid "Server write error." -msgstr "Írási hiba a szerveren." - -#: lib/Horde/Imap/Client/Socket.php:4551 -msgid "The comparison algorithm was not recognized by the server." -msgstr "A szerver nem ismerte fel az összehasonlító algoritmust." - -#: lib/Horde/Imap/Client/Socket.php:602 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "Az IMAP4rev1 (RFC 3501) nem támogatott a szerveren." - -#: lib/Horde/Imap/Client/Socket.php:4677 -msgid "The mail server has denied the request." -msgstr "A levelezőszerver elutasította a kérést." - -#: lib/Horde/Imap/Client/Socket.php:4661 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "A levelező szerver hibás adatot jelen a postafiókban." - -#: lib/Horde/Imap/Client/Socket.php:4463 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "A levelező szerver nem tudta a levelet beolvasni." - -#: lib/Horde/Imap/Client/Socket.php:4416 -msgid "" -"The mail server was unable to parse the contents of the mail message: %s" -msgstr "A levelező szerver nem tudta a levelet beolvasni: %s" - -#: lib/Horde/Imap/Client/Socket.php:4569 -msgid "The metadata item could not be saved because it is too large." -msgstr "A metaadatok mentése nem sikerült, mert túl nagy méretűek." - -#: lib/Horde/Imap/Client/Socket.php:4587 -msgid "" -"The metadata item could not be saved because the maximum number of " -"annotations has been exceeded." -msgstr "" -"A metaadatok mentése nem sikerült, mert túlléptük a megjegyzések maximális " -"számát." - -#: lib/Horde/Imap/Client/Socket.php:4578 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "" -"A metaadatok mentése nem sikerült, mert a szerver nem támogatja a privát " -"megjegyzéseket." - -#: lib/Horde/Imap/Client/Socket.php:4695 -msgid "The object could not be created because it already exists." -msgstr "Az objektum létrehozása nem sikerült, mert az már létezik." - -#: lib/Horde/Imap/Client/Socket.php:4704 -msgid "The object could not be deleted because it does not exist." -msgstr "Az elem nem létezik, ezért a törlése nem sikerült." - -#: lib/Horde/Imap/Client/Socket.php:4686 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "" -"A művelet végrehajtása nem sikerült, mert túlléptük a rendelkezésre álló " -"kvóta méretet." - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:44 -msgid "The server does not support the %s extension." -msgstr "A szerver nem támogatja a %s kiterjesztést." - -#: lib/Horde/Imap/Client/Socket.php:4713 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "Az egyedi paraméter nem támogatott." - -#: lib/Horde/Imap/Client/Socket.php:4647 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "Hiba történt a művelet végrehajtása során. Kérem próbálja meg később." - -#: lib/Horde/Imap/Client/Socket.php:691 -#: lib/Horde/Imap/Client/Socket/Pop3.php:339 -msgid "Unexpected response from server when authenticating." -msgstr "Váratlan válasz a távoli szervertőt a bejelentkezés során." - -#: lib/Horde/Imap/Client/Socket.php:728 -#: lib/Horde/Imap/Client/Socket/Pop3.php:385 -msgid "Unknown authentication method: %s" -msgstr "Ismeretlen bejelentkezési módszer: %s" - -#: lib/Horde/Imap/Client/Socket.php:4638 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "Ön nem jogosult a művelet végrehajtására." diff --git a/lib/horde/locale/hu/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/hu/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index d6e5cc68716..00000000000 Binary files a/lib/horde/locale/hu/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/hu/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/hu/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 634ab54a4b4..00000000000 --- a/lib/horde/locale/hu/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,69 +0,0 @@ -# Hungarian translations for Horde_Mime module. -# Copyright 2010-2013 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime \n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2014-05-29 09:14+0200\n" -"PO-Revision-Date: 2014-07-14 11:35+0200\n" -"Last-Translator: Andras Galos \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: hu\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "Kézbesítési értesítés" - -#: lib/Horde/Mime/Mail.php:421 -msgid "HTML Version of Message" -msgstr "A levél HTML változata" - -#: lib/Horde/Mime/Headers.php:547 -msgid "List-Archive" -msgstr "Lista archívum" - -#: lib/Horde/Mime/Headers.php:542 -msgid "List-Help" -msgstr "Lista súgó" - -#: lib/Horde/Mime/Headers.php:549 -msgid "List-Id" -msgstr "Lista azonosító" - -#: lib/Horde/Mime/Headers.php:545 -msgid "List-Owner" -msgstr "Lista tulajdonos" - -#: lib/Horde/Mime/Headers.php:546 -msgid "List-Post" -msgstr "Lista levélírás" - -#: lib/Horde/Mime/Headers.php:544 -msgid "List-Subscribe" -msgstr "Lista feliratkozás (subscribe)" - -#: lib/Horde/Mime/Headers.php:543 -msgid "List-Unsubscribe" -msgstr "Lista leiratkozás (unsubscribe)" - -#: lib/Horde/Mime/Mail.php:419 -msgid "Plaintext Version of Message" -msgstr "A levél egyszerű szöveges változata" - -#: lib/Horde/Mime/Mdn.php:200 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"A levél, melyet %s napján küldött %s címzettnek \"%s\" tárgyban, a címzett " -"számítógépén megjelent.\n" -"Ez nem jelent garanciát arra, hogy a levelet el is olvasták és meg is " -"értették." diff --git a/lib/horde/locale/id/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/id/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 70543261679..00000000000 Binary files a/lib/horde/locale/id/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/id/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/id/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 8ae0c8c99c9..00000000000 --- a/lib/horde/locale/id/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,25 +0,0 @@ -# Indonesian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ASCII\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "" - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "Izin" diff --git a/lib/horde/locale/id/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/id/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 3bc23ceb792..00000000000 Binary files a/lib/horde/locale/id/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/id/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/id/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index ea6805d956d..00000000000 --- a/lib/horde/locale/id/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,71 +0,0 @@ -# Indonesian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ASCII\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Pengganti alamat email" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Daftar Topik Bantuan" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -#, fuzzy -msgid "List-Subscribe" -msgstr "Angka/huruf/simbol yang ditulis dibawah garis baris teks" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/is/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/is/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 71938c4918c..00000000000 Binary files a/lib/horde/locale/is/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/is/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/is/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 0faeabb7a7e..00000000000 --- a/lib/horde/locale/is/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,25 +0,0 @@ -# Icelandic translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "" - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "Persónulegt" diff --git a/lib/horde/locale/is/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/is/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index e615918c106..00000000000 Binary files a/lib/horde/locale/is/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/is/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/is/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 20c8f4a0191..00000000000 --- a/lib/horde/locale/is/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,73 +0,0 @@ -# Icelandic translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Netfang" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Hjálp" - -#: lib/Horde/Mime/Headers.php:521 -#, fuzzy -msgid "List-Id" -msgstr "Hjálp" - -#: lib/Horde/Mime/Headers.php:517 -#, fuzzy -msgid "List-Owner" -msgstr "Hjálp" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -#, fuzzy -msgid "List-Subscribe" -msgstr "Efni" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/it/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/it/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 8056dfabd00..00000000000 Binary files a/lib/horde/locale/it/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/it/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/it/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 3b992cb0a4d..00000000000 --- a/lib/horde/locale/it/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Italian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "Nessun suono" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "Permessi negati" diff --git a/lib/horde/locale/it/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/it/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 326ebced072..00000000000 Binary files a/lib/horde/locale/it/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/it/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/it/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 038a717841a..00000000000 --- a/lib/horde/locale/it/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,73 +0,0 @@ -# Italian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Notifica Disposizione" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "HTML Versione del Messaggio" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Carattere non valido nell'indirizzo email : %s" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "Elenco-Archivio" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "elenco-Aiuto" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "Elenco-Id" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "Elenco-Proprietario" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "Elenco-Post" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "Elenco-Sottoscrivi" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "Elenco-Revoca sottoscrizione" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "Messaggio come testo semplice" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"In messaggio inviato su %s a %s con oggetto \"%s\" è stato mostrato.\n" -"\n" -"Non c'è garanzia che il messaggio sia stato letto o compreso." diff --git a/lib/horde/locale/ja/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/ja/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 2c15ac8035c..00000000000 Binary files a/lib/horde/locale/ja/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/ja/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/ja/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 3b6227399b2..00000000000 --- a/lib/horde/locale/ja/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,27 +0,0 @@ -# Japanese translation for Horde. -# Copyright 2004-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde package. -# Hiromi Kimura -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-01-17 12:38+0100\n" -"PO-Revision-Date: 2012-10-14 11:19+0900\n" -"Last-Translator: Hiromi Kimura \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: ja\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 1.5.4\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "見つかりません" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "アクセスは拒否されました" diff --git a/lib/horde/locale/ja/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/ja/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index d7fab9be194..00000000000 Binary files a/lib/horde/locale/ja/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/ja/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/ja/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index bc98ae29b48..00000000000 --- a/lib/horde/locale/ja/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,262 +0,0 @@ -# Japanese translation for Horde. -# Copyright (C) 2012-2013 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# Hiromi Kimura -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2014-01-28 00:26-0700\n" -"PO-Revision-Date: 2014-02-22 12:49+0900\n" -"Last-Translator: Hiromi Kimura \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: ja\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 1.6.3\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:34 -#, php-format -msgid "%s not supported on POP3 servers." -msgstr "POP3サーバは %s をサポートしていません。" - -#: lib/Horde/Imap/Client/Socket.php:4635 -msgid "Authentication credentials have expired." -msgstr "認証用証明書は期限切れです。" - -#: lib/Horde/Imap/Client/Socket.php:4619 -msgid "Authentication failed." -msgstr "認証に失敗しました。" - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:158 -msgid "Authentication failure." -msgstr "認証できません。" - -#: lib/Horde/Imap/Client/Socket.php:4627 -msgid "Authentication was successful, but authorization failed." -msgstr "認証は成功しましたが、認可に失敗しました。" - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:44 -msgid "Bad tagged response." -msgstr "不正なタグ応答です。" - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:45 -msgid "Cannot convert search query text to new charset" -msgstr "検索文字列を新しい文字セットに変換できません" - -#: lib/Horde/Imap/Client/Base.php:2032 lib/Horde/Imap/Client/Base.php:2095 -msgid "Cannot expunge read-only mailbox." -msgstr "読み出し専用メールボックスは削除できません。" - -#: lib/Horde/Imap/Client/Socket.php:4413 -msgid "Charset used in search query is not supported on the mail server." -msgstr "検索文字中の文字セットはメールサーバではサポートされていません。" - -#: lib/Horde/Imap/Client/Socket.php:1077 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "メールボックス \"%s\" が開けません。" - -#: lib/Horde/Imap/Client/Socket.php:393 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "IMAPサーバへのTLS接続はオープンできませんでした。" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:194 -#: lib/Horde/Imap/Client/Socket/Pop3.php:208 -msgid "Could not open secure connection to the POP3 server." -msgstr "POP3サーバへの安全な接続はオープンできませんでした。" - -#: lib/Horde/Imap/Client/Socket.php:4519 -msgid "Could not save message data because it is too large." -msgstr "メッセージが大きすぎるので保存できません。" - -#: lib/Horde/Imap/Client/Socket.php:4510 -msgid "Could not save message on server." -msgstr "メッセージをサーバーに保存できません。" - -#: lib/Horde/Imap/Client/Socket.php:574 -#: lib/Horde/Imap/Client/Socket/Pop3.php:284 -msgid "Error connecting to mail server." -msgstr "メールサーバへの接続に失敗しました。" - -#: lib/Horde/Imap/Client/Utf7imap.php:128 -#: lib/Horde/Imap/Client/Utf7imap.php:156 -#: lib/Horde/Imap/Client/Utf7imap.php:163 -#: lib/Horde/Imap/Client/Utf7imap.php:225 -#: lib/Horde/Imap/Client/Utf7imap.php:245 -#: lib/Horde/Imap/Client/Utf7imap.php:252 -#: lib/Horde/Imap/Client/Utf7imap.php:263 -#: lib/Horde/Imap/Client/Utf7imap.php:272 -msgid "Error converting UTF7-IMAP string." -msgstr "UTF7-IMAP文字列への変換エラーです。" - -#: lib/Horde/Imap/Client/Socket.php:4081 -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:71 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:180 -#: lib/Horde/Imap/Client/Socket/Pop3.php:1191 -msgid "Error when communicating with the mail server." -msgstr "メールサーバとの通信エラーです。" - -#: lib/Horde/Imap/Client/Socket.php:4200 -msgid "IMAP Server closed the connection." -msgstr "IMAP サーバは接続を閉じました。" - -#: lib/Horde/Imap/Client/Socket.php:4186 -msgid "IMAP error reported by server." -msgstr "サーバはIMAPエラーを報告しました。" - -#: lib/Horde/Imap/Client/Socket.php:3682 -#, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "不正なメタデータ項目:\"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:3768 -#, php-format -msgid "Invalid METADATA value type \"%s\"." -msgstr "不正なメタデータの種類 \"%s\"." - -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:121 -msgid "Mail server closed the connection unexpectedly." -msgstr "メールサーバとの接続が予期せずに切断されました。" - -#: lib/Horde/Imap/Client/Socket.php:542 -msgid "Mail server denied authentication." -msgstr "メールサーバは認証を拒否しました。" - -#: lib/Horde/Imap/Client/Base.php:2365 lib/Horde/Imap/Client/Base.php:2685 -#: lib/Horde/Imap/Client/Base.php:2950 lib/Horde/Imap/Client/Base.php:3035 -msgid "Mailbox does not support mod-sequences." -msgstr "メールボックスは mod-sequence をサポートしていません。" - -#: lib/Horde/Imap/Client/Socket.php:469 -msgid "No supported IMAP authentication method could be found." -msgstr "サポートされた IMAP 認証が見つかりません。" - -#: lib/Horde/Imap/Client/Socket.php:4643 -msgid "Operation failed due to a lack of a secure connection." -msgstr "安全な接続ができないため操作に失敗しました。" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1250 -msgid "POP3 error reported by server." -msgstr "サーバは POP3 エラーを報告しました。" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:253 -msgid "POP3 server denied authentication." -msgstr "POP3 サーバは認証を拒否しました。" - -#: lib/Horde/Imap/Client/Socket.php:4611 -msgid "Remote server is temporarily unavailable." -msgstr "リモートサーバは一時的に使用不能です。" - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:63 -msgid "Server closed the connection unexpectedly." -msgstr "サーバは接続を予期せずに切断しました。" - -#: lib/Horde/Imap/Client/Socket.php:381 -msgid "Server does not support TLS connections." -msgstr "サーバは TLS 接続をサポートしていません。" - -#: lib/Horde/Imap/Client/Socket/Pop3.php:194 -msgid "Server does not support secure connections." -msgstr "サーバは安全な接続をサポートしていません。" - -#: lib/Horde/Imap/Client/Socket.php:594 -msgid "Server rejected connection." -msgstr "サーバは接続を拒絶しました。" - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:42 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:54 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:87 -msgid "Server write error." -msgstr "サーバ書き込みエラー。" - -#: lib/Horde/Imap/Client/Socket.php:4564 -msgid "The comparison algorithm was not recognized by the server." -msgstr "比較アルゴリズムがサーバで認識されませんでした。" - -#: lib/Horde/Imap/Client/Socket.php:603 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "メールサーバは IMAP4rev1(RFC3501) をサポートしていません。" - -#: lib/Horde/Imap/Client/Socket.php:4690 -msgid "The mail server has denied the request." -msgstr "メールサーバは要求を拒否しました。" - -#: lib/Horde/Imap/Client/Socket.php:4674 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "" -"メールサーバはあなたのメールボックスのデータが壊れていると報告しています。" - -#: lib/Horde/Imap/Client/Socket.php:4476 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "メールサーバはメッセージの内容を解析できませんでした。" - -#: lib/Horde/Imap/Client/Socket.php:4429 -#, php-format -msgid "" -"The mail server was unable to parse the contents of the mail message: %s" -msgstr "メールサーバはメッセージの内容を解析できませんでした:%s" - -#: lib/Horde/Imap/Client/Socket.php:4582 -msgid "The metadata item could not be saved because it is too large." -msgstr "メタデータが大きすぎたため、保存できませんでした。" - -#: lib/Horde/Imap/Client/Socket.php:4600 -msgid "" -"The metadata item could not be saved because the maximum number of " -"annotations has been exceeded." -msgstr "注釈の最大数を超過しているため、メタデータは保存できませんでした。" - -#: lib/Horde/Imap/Client/Socket.php:4591 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "" -"サーバが私的な注釈をサポートしていないので、メタデータは保存できませんでし" -"た。" - -#: lib/Horde/Imap/Client/Socket.php:4708 -msgid "The object could not be created because it already exists." -msgstr "オブジェクトは既に存在するので作成されませんでした。" - -#: lib/Horde/Imap/Client/Socket.php:4717 -msgid "The object could not be deleted because it does not exist." -msgstr "オブジェクトは存在しないので削除できませんでした。" - -#: lib/Horde/Imap/Client/Socket.php:4699 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "メールサーバのクォータを超過しているので、操作は失敗しました。" - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:46 -#, php-format -msgid "The server does not support the %s extension." -msgstr "サーバは %s 拡張をサポートしていません。" - -#: lib/Horde/Imap/Client/Socket.php:4726 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "メールボックスの特別な属性の使用はサポートされていません。" - -#: lib/Horde/Imap/Client/Socket.php:4660 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "この操作には一時的な問題がありました。後で再度試して下さい。" - -#: lib/Horde/Imap/Client/Socket.php:692 -#: lib/Horde/Imap/Client/Socket/Pop3.php:339 -msgid "Unexpected response from server when authenticating." -msgstr "認証時にサーバから予期しない応答がありました。" - -#: lib/Horde/Imap/Client/Socket.php:729 -#: lib/Horde/Imap/Client/Socket/Pop3.php:385 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "不明な認証方式です:%s" - -#: lib/Horde/Imap/Client/Socket.php:4651 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "あなたにはこの操作を実行するのに十分なアクセス権を持っていません。" diff --git a/lib/horde/locale/ja/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/ja/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 6e08bfbcf25..00000000000 Binary files a/lib/horde/locale/ja/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/ja/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/ja/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 2842135b8d0..00000000000 --- a/lib/horde/locale/ja/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,69 +0,0 @@ -# Japanese translation for Horde. -# Copyright 2004-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde package. -# Hiromi Kimura -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-08-29 13:30+0200\n" -"PO-Revision-Date: 2012-10-14 11:30+0900\n" -"Last-Translator: Hiromi Kimura \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: ja\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 1.5.4\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "開封通知" - -#: lib/Horde/Mime/Mail.php:419 -msgid "HTML Version of Message" -msgstr "HTML 版のメッセージ" - -#: lib/Horde/Mime/Headers.php:540 -msgid "List-Archive" -msgstr "List-Archive" - -#: lib/Horde/Mime/Headers.php:535 -msgid "List-Help" -msgstr "List-Help" - -#: lib/Horde/Mime/Headers.php:542 -msgid "List-Id" -msgstr "List-Id" - -#: lib/Horde/Mime/Headers.php:538 -msgid "List-Owner" -msgstr "List-Owner" - -#: lib/Horde/Mime/Headers.php:539 -msgid "List-Post" -msgstr "List-Post" - -#: lib/Horde/Mime/Headers.php:537 -msgid "List-Subscribe" -msgstr "List-Subscribe" - -#: lib/Horde/Mime/Headers.php:536 -msgid "List-Unsubscribe" -msgstr "List-Unsubscribe" - -#: lib/Horde/Mime/Mail.php:417 -msgid "Plaintext Version of Message" -msgstr "メッセージのプレインテキスト版" - -#: lib/Horde/Mime/Mdn.php:200 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"日付:%s、宛先:%s、件名:\"%s\" のメッセージが表示されました。\n" -"しかし、相手に読まれたか、あるいは了解されたかは保証できません。" diff --git a/lib/horde/locale/km/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/km/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 71938c4918c..00000000000 Binary files a/lib/horde/locale/km/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/km/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/km/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index df123deaf68..00000000000 --- a/lib/horde/locale/km/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,25 +0,0 @@ -# Khmer translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "" - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "សិទ្ធិ​ត្រូវ​បាន​បដិសេធ" diff --git a/lib/horde/locale/km/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/km/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index e615918c106..00000000000 Binary files a/lib/horde/locale/km/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/km/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/km/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 2723fc41115..00000000000 --- a/lib/horde/locale/km/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,71 +0,0 @@ -# Khmer translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "ប្ដូរ​អាសយដ្ឋាន​អ៊ីមែល" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "ជំនួយ" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -#, fuzzy -msgid "List-Subscribe" -msgstr "អក្សរ​តូច​ក្រោម" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/ko/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/ko/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 9cea0a32dd7..00000000000 Binary files a/lib/horde/locale/ko/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/ko/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/ko/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 056201d87c3..00000000000 --- a/lib/horde/locale/ko/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Korean translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "" - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "개인 메일" diff --git a/lib/horde/locale/ko/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/ko/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index ff34a1b5884..00000000000 Binary files a/lib/horde/locale/ko/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/ko/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/ko/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index ab05a783ffb..00000000000 --- a/lib/horde/locale/ko/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,76 +0,0 @@ -# Korean translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "잘못된 이메일 주소" - -#: lib/Horde/Mime/Headers.php:519 -#, fuzzy -msgid "List-Archive" -msgstr "사용하지 않는 메일함 숨김" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "도움알 목차" - -#: lib/Horde/Mime/Headers.php:521 -#, fuzzy -msgid "List-Id" -msgstr "도움알 목차" - -#: lib/Horde/Mime/Headers.php:517 -#, fuzzy -msgid "List-Owner" -msgstr "도움알 목차" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -#, fuzzy -msgid "List-Subscribe" -msgstr "사용하지 않는 메일함 숨김" - -#: lib/Horde/Mime/Headers.php:515 -#, fuzzy -msgid "List-Unsubscribe" -msgstr "사용하지 않는 메일함 숨김" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/lt/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/lt/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 2797485da07..00000000000 Binary files a/lib/horde/locale/lt/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/lt/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/lt/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 6674810f2f9..00000000000 --- a/lib/horde/locale/lt/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Lithuanian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Vilius Šumskas , 2011. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2011-05-28 01:09+0300\n" -"PO-Revision-Date: 2011-06-27 23:04+0300\n" -"Last-Translator: Vilius Šumskas \n" -"Language-Team: Lithuanian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n" -"%100<10 || n%100>=20) ? 1 : 2);\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Nerasta" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Neužtenka teisių" diff --git a/lib/horde/locale/lt/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/lt/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index a31044ba237..00000000000 Binary files a/lib/horde/locale/lt/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/lt/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/lt/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 4c0bc5d029b..00000000000 --- a/lib/horde/locale/lt/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,74 +0,0 @@ -# Lithuanian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Vilius Šumskas , 2011. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2011-05-28 01:09+0300\n" -"PO-Revision-Date: 2011-06-28 00:44+0300\n" -"Last-Translator: Vilius Šumskas \n" -"Language-Team: Lithuanian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n" -"%100<10 || n%100>=20) ? 1 : 2);\n" - -#: lib/Horde/Mime/Mdn.php:191 -msgid "Disposition Notification" -msgstr "Laiško pristatymo pranešimai" - -#: lib/Horde/Mime/Mail.php:446 -msgid "HTML Version of Message" -msgstr "Laiško HTML versija" - -#: lib/Horde/Mime/Mail.php:390 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Neleistinas simbolis el. pašto adrese: %s." - -#: lib/Horde/Mime/Headers.php:534 -msgid "List-Archive" -msgstr "Konferencijos archyvas" - -#: lib/Horde/Mime/Headers.php:529 -msgid "List-Help" -msgstr "Konferencijos pagalba" - -#: lib/Horde/Mime/Headers.php:536 -msgid "List-Id" -msgstr "Konferencijos ID" - -#: lib/Horde/Mime/Headers.php:532 -msgid "List-Owner" -msgstr "Konferencijos savininkas" - -#: lib/Horde/Mime/Headers.php:533 -msgid "List-Post" -msgstr "Rašyti į konferenciją" - -#: lib/Horde/Mime/Headers.php:531 -msgid "List-Subscribe" -msgstr "Prisijungti prie konferencijos" - -#: lib/Horde/Mime/Headers.php:530 -msgid "List-Unsubscribe" -msgstr "Atsijungti nuo konferencijos" - -#: lib/Horde/Mime/Mail.php:444 -msgid "Plaintext Version of Message" -msgstr "Tekstinė laiško versija" - -#: lib/Horde/Mime/Mdn.php:202 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Laiškas išsiųstas %s adresatui %s tema \"%s\" buvo parodytas.\n" -"\n" -"Tačiau tai negarantuoja kad laiškas buvo perskaitytas arba suprastas." diff --git a/lib/horde/locale/lv/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/lv/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 9a0e2f350c0..00000000000 Binary files a/lib/horde/locale/lv/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/lv/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/lv/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index c9f184dc853..00000000000 --- a/lib/horde/locale/lv/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,41 +0,0 @@ -# Latvian translations for Horde_Exception package. -# Copyright 2011-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception package. -# Automatically generated, 2011. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2011-02-02 16:17+0100\n" -"PO-Revision-Date: 2011-10-16 15:21+0300\n" -"Last-Translator: Jānis Eisaks \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: lv\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : " -"2);\n" -"X-Poedit-Language: Latvian\n" -"X-Poedit-Country: LATVIA\n" -"X-Poedit-SourceCharset: utf-8\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Nav atrasts" - -# #-#-#-#-# horde.po (Horde 2.1) #-#-#-#-# -# #-#-#-#-# lv_LV.po (Mnemo 2.1.2) #-#-#-#-# -# -# #-#-#-#-# lv_LV.po (Ingo H3 (1.1.5)) #-#-#-#-# -# #-#-#-#-# lv_LV.po (Mnemo 2.1.2) #-#-#-#-# -# -# #-#-#-#-# mnemo.po (Mnemo 2.1.2) #-#-#-#-# -# -# #-#-#-#-# ingo.po (Ingo H3 (1.1.5)) #-#-#-#-# -# #-#-#-#-# lv_LV.po (Mnemo 2.1.2) #-#-#-#-# -# -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Pieeja liegta" diff --git a/lib/horde/locale/lv/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/lv/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index bf0eec3fad1..00000000000 Binary files a/lib/horde/locale/lv/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/lv/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/lv/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 9a161642635..00000000000 --- a/lib/horde/locale/lv/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,78 +0,0 @@ -# Latvian translations for Horde_Mime package. -# Copyright 2011-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime package. -# Automatically generated, 2011. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2011-05-18 12:23+0200\n" -"PO-Revision-Date: 2011-10-16 15:21+0300\n" -"Last-Translator: Jānis Eisaks \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: lv\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : " -"2);\n" -"X-Poedit-Language: Latvian\n" -"X-Poedit-Country: LATVIA\n" -"X-Poedit-SourceCharset: utf-8\n" - -#: lib/Horde/Mime/Mdn.php:191 -msgid "Disposition Notification" -msgstr "Izlasīšanas apstiprinājums" - -#: lib/Horde/Mime/Mail.php:446 -msgid "HTML Version of Message" -msgstr "Vēstules HTML versija" - -#: lib/Horde/Mime/Mail.php:390 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Neatļauts simbols e-pasta adresē: %s." - -#: lib/Horde/Mime/Headers.php:534 -msgid "List-Archive" -msgstr "Vēstkopas arhīvs" - -#: lib/Horde/Mime/Headers.php:529 -msgid "List-Help" -msgstr "Vēstkopas palīdzība" - -#: lib/Horde/Mime/Headers.php:536 -msgid "List-Id" -msgstr "Vēstkopas ID" - -#: lib/Horde/Mime/Headers.php:532 -msgid "List-Owner" -msgstr "Vēstkopas īpašnieks" - -#: lib/Horde/Mime/Headers.php:533 -msgid "List-Post" -msgstr "Sūtījums vēstkopai" - -#: lib/Horde/Mime/Headers.php:531 -msgid "List-Subscribe" -msgstr "Parakstīties uz vēstkopu" - -#: lib/Horde/Mime/Headers.php:530 -msgid "List-Unsubscribe" -msgstr "Atrakstīties no vēstkopas" - -#: lib/Horde/Mime/Mail.php:444 -msgid "Plaintext Version of Message" -msgstr "Vēstules vienkāršā teksta versija" - -#: lib/Horde/Mime/Mdn.php:202 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"%s lietotājam %s nosūtītā vēstule ar tematu \"%s\" ir atvērta.\n" -"\n" -"Tas gan nenozīmē, ka vēstule ir izlasīta vai saprasta." diff --git a/lib/horde/locale/mk/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/mk/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 71938c4918c..00000000000 Binary files a/lib/horde/locale/mk/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/mk/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/mk/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 5786c1f8b81..00000000000 --- a/lib/horde/locale/mk/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,24 +0,0 @@ -# Macedonian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "" diff --git a/lib/horde/locale/mk/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/mk/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index e615918c106..00000000000 Binary files a/lib/horde/locale/mk/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/mk/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/mk/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 096ac3f05e2..00000000000 --- a/lib/horde/locale/mk/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,70 +0,0 @@ -# Macedonian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Излистај теми за помош" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/nb/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/nb/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index b8d6164080f..00000000000 Binary files a/lib/horde/locale/nb/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/nb/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/nb/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 8a3d26963b1..00000000000 --- a/lib/horde/locale/nb/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,27 +0,0 @@ -# Norwegian Bokmal translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "ikke funnet" - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "Rettighet" diff --git a/lib/horde/locale/nb/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/nb/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 35e4a9a5699..00000000000 Binary files a/lib/horde/locale/nb/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/nb/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/nb/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 4bc2d013638..00000000000 --- a/lib/horde/locale/nb/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,72 +0,0 @@ -# Norwegian Bokmal translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Melding om ordning" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Ugyldig mottaker adresse." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Emner i Hjelp" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -#, fuzzy -msgid "List-Subscribe" -msgstr "Undertekst" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/nl/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/nl/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index cc8c1054eea..00000000000 Binary files a/lib/horde/locale/nl/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/nl/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/nl/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index eb8f2eff688..00000000000 --- a/lib/horde/locale/nl/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,27 +0,0 @@ -# Dutch translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# -# Arjen de Korte , 2012. -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-01-17 12:38+0100\n" -"PO-Revision-Date: 2012-11-03 12:17+0100\n" -"Last-Translator: Arjen de Korte \n" -"Language-Team: Dutch \n" -"Language: nl\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Lokalize 1.4\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Niet gevonden" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Toegang geweigerd" diff --git a/lib/horde/locale/nl/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/nl/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index 56e48f64963..00000000000 Binary files a/lib/horde/locale/nl/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/nl/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/nl/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index 167ad2009ae..00000000000 --- a/lib/horde/locale/nl/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,262 +0,0 @@ -# Dutch translations for Horde_Imap_Client package. -# Copyright 2012-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# -# Automatically generated, 2012. -# Arjen de Korte , 2012. -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-11-06 16:40+0100\n" -"PO-Revision-Date: 2012-11-29 22:21+0100\n" -"Last-Translator: Arjen de Korte \n" -"Language-Team: American English \n" -"Language: nl\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Lokalize 1.4\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:25 -#, php-format -msgid "%s not supported on POP3 servers." -msgstr "%s niet ondersteund op POP3 servers." - -#: lib/Horde/Imap/Client/Socket.php:4380 -msgid "Authentication credentials have expired." -msgstr "Verificatie gegevens zijn verlopen." - -#: lib/Horde/Imap/Client/Socket.php:4364 -msgid "Authentication failed." -msgstr "Verificatie mislukt." - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:149 -msgid "Authentication failure." -msgstr "Verificatiefout." - -#: lib/Horde/Imap/Client/Socket.php:4372 -msgid "Authentication was successful, but authorization failed." -msgstr "Verificatie was succesvol, maar toestemming is geweigerd." - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:34 -msgid "Bad tagged response." -msgstr "Ongeldig gelabeld antwoord." - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:36 -msgid "Cannot convert search query text to new charset" -msgstr "Kan de zoekopdracht niet naar de nieuwe karakterset omzetten." - -#: lib/Horde/Imap/Client/Base.php:1899 lib/Horde/Imap/Client/Base.php:1958 -msgid "Cannot expunge read-only mailbox." -msgstr "Kan alleen-lezen map niet legen." - -#: lib/Horde/Imap/Client/Socket.php:4165 -msgid "Charset used in search query is not supported on the mail server." -msgstr "Karakterset in zoekopdracht wordt niet ondersteund op de mailserver." - -#: lib/Horde/Imap/Client/Socket.php:931 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "Kan map \"%s\" niet openen." - -#: lib/Horde/Imap/Client/Socket.php:335 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "Kan geen beveiligde TLS verbinding met IMAP server maken." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:189 -#: lib/Horde/Imap/Client/Socket/Pop3.php:201 -msgid "Could not open secure connection to the POP3 server." -msgstr "Kon geen beveiligde verbinding maken met de POP3 server." - -#: lib/Horde/Imap/Client/Socket.php:4265 -msgid "Could not save message data because it is too large." -msgstr "Kan bericht gegevens niet opslaan omdat het te groot is." - -#: lib/Horde/Imap/Client/Socket.php:4256 -msgid "Could not save message on server." -msgstr "Kon bericht niet opslaan op de server." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:280 -msgid "Error connecting to POP3 server." -msgstr "Er is een fout opgetreden bij het verbinden met de POP3 server." - -#: lib/Horde/Imap/Client/Socket.php:504 -msgid "Error connecting to mail server." -msgstr "Er is een fout opgetreden bij het verbinden met de mailserver." - -#: lib/Horde/Imap/Client/Utf7imap.php:117 -#: lib/Horde/Imap/Client/Utf7imap.php:142 -#: lib/Horde/Imap/Client/Utf7imap.php:146 -#: lib/Horde/Imap/Client/Utf7imap.php:205 -#: lib/Horde/Imap/Client/Utf7imap.php:222 -#: lib/Horde/Imap/Client/Utf7imap.php:226 -#: lib/Horde/Imap/Client/Utf7imap.php:234 -#: lib/Horde/Imap/Client/Utf7imap.php:240 -msgid "Error converting UTF7-IMAP string." -msgstr "Er is een fout opgetreden bij het omzetten van de UTF7-IMAP string." - -#: lib/Horde/Imap/Client/Socket.php:3683 lib/Horde/Imap/Client/Socket.php:3964 -msgid "Error when communicating with the mail server." -msgstr "Er is een fout opgetreden bij het communiceren met de mailserver." - -#: lib/Horde/Imap/Client/Socket.php:3838 -msgid "IMAP Server closed the connection." -msgstr "IMAP server heeft de verbinding beëindigd." - -#: lib/Horde/Imap/Client/Socket.php:3823 lib/Horde/Imap/Client/Socket.php:3854 -msgid "IMAP error reported by server." -msgstr "IMAP fout gerapporteerd door de server." - -#: lib/Horde/Imap/Client/Socket.php:3389 -#, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "Ongeldige METADATA invoer: \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:3476 -#, php-format -msgid "Invalid METADATA value type \"%s\"." -msgstr "Ongeldige METADATA waarde type \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:3890 -msgid "Mail server closed the connection unexpectedly." -msgstr "De mailserver heeft de verbinding onverwacht beëindigd." - -#: lib/Horde/Imap/Client/Socket.php:395 -msgid "Mail server denied authentication." -msgstr "Mailserver heeft de aanmelding geweigerd." - -#: lib/Horde/Imap/Client/Socket.php:1812 lib/Horde/Imap/Client/Socket.php:2483 -#: lib/Horde/Imap/Client/Socket.php:2504 lib/Horde/Imap/Client/Socket.php:2933 -#: lib/Horde/Imap/Client/Socket.php:2988 -msgid "Mailbox does not support mod-sequences." -msgstr "Map ondersteund geen mod-sequenties." - -#: lib/Horde/Imap/Client/Socket.php:378 -msgid "No supported IMAP authentication method could be found." -msgstr "Geen ondersteunde IMAP " - -#: lib/Horde/Imap/Client/Socket.php:4388 -msgid "Operation failed due to a lack of a secure connection." -msgstr "De bewerking vereist een beveiligde verbinding." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1096 -msgid "POP3 Server closed the connection unexpectedly." -msgstr "POP3 server heeft de verbinding onverwacht beëindigd." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1156 -msgid "POP3 error reported by server." -msgstr "POP3 fout gemeld door de server." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:240 -msgid "POP3 server denied authentication." -msgstr "POP3 server heeft verificatie geweigerd." - -#: lib/Horde/Imap/Client/Socket.php:4356 -msgid "Remote server is temporarily unavailable." -msgstr "Server op afstand is tijdelijk niet beschikbaar." - -#: lib/Horde/Imap/Client/Socket.php:323 -msgid "Server does not support TLS connections." -msgstr "Server ondersteunt geen TLS verbindingen." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:189 -msgid "Server does not support secure connections." -msgstr "Server ondersteunt geen beveiligde verbindingen." - -#: lib/Horde/Imap/Client/Socket.php:527 -msgid "Server rejected connection." -msgstr "Server heeft verbinding geweigerd." - -#: lib/Horde/Imap/Client/Socket.php:3748 -msgid "Server write error." -msgstr "Server schrijffout." - -#: lib/Horde/Imap/Client/Socket.php:4309 -msgid "The comparison algorithm was not recognized by the server." -msgstr "Het vergelijkingsalgoritme wordt niet herkend door de server" - -#: lib/Horde/Imap/Client/Socket.php:536 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "De mailserver ondersteunt IMAP4rev1 (RFC 3501) niet." - -#: lib/Horde/Imap/Client/Socket.php:4435 -msgid "The mail server has denied the request." -msgstr "De mailserver heeft het verzoek geweigerd." - -#: lib/Horde/Imap/Client/Socket.php:4419 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "De mailserver rapporteert beschadigde data in uw map." - -#: lib/Horde/Imap/Client/Socket.php:4177 lib/Horde/Imap/Client/Socket.php:4222 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "" -"De mailserver was niet in staat om de inhoud van het bericht te verwerken." - -#: lib/Horde/Imap/Client/Socket.php:4327 -msgid "The metadata item could not be saved because it is too large." -msgstr "Het metadata item kon niet worden opgeslagen omdat het te groot is." - -#: lib/Horde/Imap/Client/Socket.php:4345 -msgid "" -"The metadata item could not be saved because the maximum number of " -"annotations has been exceeded." -msgstr "" -"Het metadata item kon niet worden opgeslagen omdat het maximale aantal " -"annotaties wordt overschreden." - -#: lib/Horde/Imap/Client/Socket.php:4336 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "" -"Het metadata item kon niet worden opgeslagen omdat de server geen privé " -"annotaties ondersteund." - -#: lib/Horde/Imap/Client/Socket.php:4453 -msgid "The object could not be created because it already exists." -msgstr "Het object kon niet worden aangemaakt omdat het al bestaat." - -#: lib/Horde/Imap/Client/Socket.php:4462 -msgid "The object could not be deleted because it does not exist." -msgstr "Het object kon niet worden verwijderd omdat het niet bestaat." - -#: lib/Horde/Imap/Client/Socket.php:4444 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "" -"De bewerking is mislukt omdat het quotum op de mailserver is overschreden." - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:36 -#, php-format -msgid "The server does not support the %s extension." -msgstr "De server ondersteunt de %s extensie niet." - -#: lib/Horde/Imap/Client/Socket.php:4471 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "" -"Het special-use attribuut dat is gevraagd voor de map wordt niet ondersteund." - -#: lib/Horde/Imap/Client/Socket.php:4405 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "" -"Er is een tijdelijk probleem opgetreden bij het uitvoeren van deze " -"bewerking. Probeer het later nog eens." - -#: lib/Horde/Imap/Client/Socket.php:604 -#: lib/Horde/Imap/Client/Socket/Pop3.php:334 -msgid "Unexpected response from server when authenticating." -msgstr "Onverwacht antwoord van server bij de verificatie." - -#: lib/Horde/Imap/Client/Socket.php:648 -#: lib/Horde/Imap/Client/Socket/Pop3.php:374 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "Onbekende verificatie methode: %s" - -#: lib/Horde/Imap/Client/Socket.php:4396 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "U heeft onvoldoende rechten om deze bewerking uit te voeren." diff --git a/lib/horde/locale/nl/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/nl/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index e5acf5df8b7..00000000000 Binary files a/lib/horde/locale/nl/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/nl/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/nl/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 8de2827029e..00000000000 --- a/lib/horde/locale/nl/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,71 +0,0 @@ -# Dutch translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# -# Arjen de Korte , 2012. -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-08-29 13:30+0200\n" -"PO-Revision-Date: 2012-11-03 12:15+0100\n" -"Last-Translator: Arjen de Korte \n" -"Language-Team: Dutch \n" -"Language: nl\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Lokalize 1.4\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "Ontvangstbevestiging" - -#: lib/Horde/Mime/Mail.php:419 -msgid "HTML Version of Message" -msgstr "HTML versie van bericht" - -#: lib/Horde/Mime/Headers.php:540 -msgid "List-Archive" -msgstr "Lijst-Archief" - -#: lib/Horde/Mime/Headers.php:535 -msgid "List-Help" -msgstr "Lijst-Hulp" - -#: lib/Horde/Mime/Headers.php:542 -msgid "List-Id" -msgstr "Lijst-ID" - -#: lib/Horde/Mime/Headers.php:538 -msgid "List-Owner" -msgstr "Lijst-Eigenaar" - -#: lib/Horde/Mime/Headers.php:539 -msgid "List-Post" -msgstr "Lijst-Adres" - -#: lib/Horde/Mime/Headers.php:537 -msgid "List-Subscribe" -msgstr "Lijst-Aanmelding" - -#: lib/Horde/Mime/Headers.php:536 -msgid "List-Unsubscribe" -msgstr "Lijst-Afmelding" - -#: lib/Horde/Mime/Mail.php:417 -msgid "Plaintext Version of Message" -msgstr "Platte tekst versie van bericht" - -#: lib/Horde/Mime/Mdn.php:200 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Het bericht dat u op %s stuurde aan %s met als onderwerp \"%s\" is " -"weergegeven.\n" -"\n" -"Er is geen garantie dat het bericht is gelezen of begrepen." diff --git a/lib/horde/locale/nn/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/nn/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index b8d6164080f..00000000000 Binary files a/lib/horde/locale/nn/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/nn/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/nn/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index ab3a60c03fd..00000000000 --- a/lib/horde/locale/nn/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Norwegian Nynorsk translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "" - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "Tilgang" diff --git a/lib/horde/locale/nn/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/nn/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 427504f5af3..00000000000 Binary files a/lib/horde/locale/nn/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/nn/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/nn/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 9551f616ca8..00000000000 --- a/lib/horde/locale/nn/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,71 +0,0 @@ -# Norwegian Nynorsk translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Vis emne frå Hjelp" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/pl/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/pl/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index ed9a15d9a56..00000000000 Binary files a/lib/horde/locale/pl/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/pl/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/pl/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 7fcdb9264d6..00000000000 --- a/lib/horde/locale/pl/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,28 +0,0 @@ -# Polish translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " -"|| n%100>=20) ? 1 : 2);\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "%s nieznaleziony." - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "Uprawnienie" diff --git a/lib/horde/locale/pl/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/pl/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 03308bc72dd..00000000000 Binary files a/lib/horde/locale/pl/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/pl/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/pl/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 2b3d1f06bad..00000000000 --- a/lib/horde/locale/pl/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,76 +0,0 @@ -# Polish translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " -"|| n%100>=20) ? 1 : 2);\n" - -#: lib/Horde/Mime/Mdn.php:202 -#, fuzzy -msgid "Disposition Notification" -msgstr "Rozmieszczenie" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Nieprawidłowy adres docelowy." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Wyświetl tematy pomocy" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -#, fuzzy -msgid "List-Subscribe" -msgstr "Podkreślenie" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, fuzzy, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Wiadomość wysłana %s do %s z tematem \"%s\" została wyświetlona.\n" -"Nie ma gwarancji, że wiadomość została przeczytana albo zrozumiana." diff --git a/lib/horde/locale/pt/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/pt/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 39337a359a2..00000000000 Binary files a/lib/horde/locale/pt/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/pt/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/pt/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index cedc593d6ce..00000000000 --- a/lib/horde/locale/pt/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Portuguese translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "Não encontrado." - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "Permissão Negada" diff --git a/lib/horde/locale/pt/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/pt/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 4eb07779c49..00000000000 Binary files a/lib/horde/locale/pt/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/pt/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/pt/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 2ccb4680311..00000000000 --- a/lib/horde/locale/pt/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,72 +0,0 @@ -# Portuguese translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Notificação de Disposição" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Endereço de destino inválido." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "Listagem-Arquivo" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "Listagem-Ajuda" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "ID da Lista" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "Listagem-Dono" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "Listagem-Submissões" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "Listagem-Subscritas" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "Listagem-Não subscritas" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, fuzzy, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"A mensagem enviada em %s para %s com assunto \"%s\" foi mostrada.\n" -"Não há garantia de que a mensagem tenha sido realmente lida ou compreendida." diff --git a/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 1984fc520e2..00000000000 Binary files a/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index dbe62610fd6..00000000000 --- a/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Portuguese translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-01-17 12:38+0100\n" -"PO-Revision-Date: 2012-03-27 22:56-0300\n" -"Last-Translator: Luis Felipe Marzagao \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Não Encontrado" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Permissão Negada" diff --git a/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index dd64651d5d1..00000000000 Binary files a/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 9fe54c615cb..00000000000 --- a/lib/horde/locale/pt_BR/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,69 +0,0 @@ -# Portuguese translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2014-06-04 11:28+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "Notificação de Disposição" - -#: lib/Horde/Mime/Mail.php:421 -msgid "HTML Version of Message" -msgstr "Versão HTML da Mensagem" - -#: lib/Horde/Mime/Headers.php:547 -msgid "List-Archive" -msgstr "List-Archive" - -#: lib/Horde/Mime/Headers.php:542 -msgid "List-Help" -msgstr "List-Help" - -#: lib/Horde/Mime/Headers.php:549 -msgid "List-Id" -msgstr "List-Id" - -#: lib/Horde/Mime/Headers.php:545 -msgid "List-Owner" -msgstr "List-Owner" - -#: lib/Horde/Mime/Headers.php:546 -msgid "List-Post" -msgstr "List-Post" - -#: lib/Horde/Mime/Headers.php:544 -msgid "List-Subscribe" -msgstr "List-Subscribe" - -#: lib/Horde/Mime/Headers.php:543 -msgid "List-Unsubscribe" -msgstr "List-Unsubscribe" - -#: lib/Horde/Mime/Mail.php:419 -msgid "Plaintext Version of Message" -msgstr "Versão da Mensagem em Texto Puro" - -#: lib/Horde/Mime/Mdn.php:200 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"A mensagem enviada em %s para %s com o assunto \"%s\" foi exibida.\n" -"\n" -"Isto não garante que a mensagem foi lida ou entendida." diff --git a/lib/horde/locale/ro/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/ro/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 212e68824f4..00000000000 Binary files a/lib/horde/locale/ro/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/ro/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/ro/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index e9bf5692679..00000000000 --- a/lib/horde/locale/ro/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Romanian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ASCII\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " -"20)) ? 1 : 2;\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "" diff --git a/lib/horde/locale/ro/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/ro/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 7350a190fab..00000000000 Binary files a/lib/horde/locale/ro/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/ro/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/ro/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index d6adbbc2c58..00000000000 --- a/lib/horde/locale/ro/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,72 +0,0 @@ -# Romanian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ASCII\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " -"20)) ? 1 : 2;\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Lista subiectelor din Help" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/ru/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/ru/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 0aa090c6a13..00000000000 Binary files a/lib/horde/locale/ru/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/ru/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/ru/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 914afe25794..00000000000 --- a/lib/horde/locale/ru/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,30 +0,0 @@ -# Russian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%" -"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "Отменить изменения" - -# #-#-#-#-# ru_RU.po (Mnemo H3 2.2) #-#-#-#-# -# fuzzy -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "Изменить права доступа" diff --git a/lib/horde/locale/ru/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/ru/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 9a919d8a982..00000000000 Binary files a/lib/horde/locale/ru/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/ru/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/ru/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 2c15d87e8b5..00000000000 --- a/lib/horde/locale/ru/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,84 +0,0 @@ -# Russian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%" -"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: lib/Horde/Mime/Mdn.php:202 -#, fuzzy -msgid "Disposition Notification" -msgstr "Настройки оповещения" - -#: lib/Horde/Mime/Mail.php:460 -#, fuzzy -msgid "HTML Version of Message" -msgstr "Следующее сообшение" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Рабочий адрес" - -# fuzzy -#: lib/Horde/Mime/Headers.php:519 -#, fuzzy -msgid "List-Archive" -msgstr "Искать" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Список разделов подсказки" - -#: lib/Horde/Mime/Headers.php:521 -#, fuzzy -msgid "List-Id" -msgstr "Список разделов подсказки" - -#: lib/Horde/Mime/Headers.php:517 -#, fuzzy -msgid "List-Owner" -msgstr "Список разделов подсказки" - -#: lib/Horde/Mime/Headers.php:518 -#, fuzzy -msgid "List-Post" -msgstr "Список разделов подсказки" - -# fuzzy -#: lib/Horde/Mime/Headers.php:516 -#, fuzzy -msgid "List-Subscribe" -msgstr "Искать" - -# fuzzy -#: lib/Horde/Mime/Headers.php:515 -#, fuzzy -msgid "List-Unsubscribe" -msgstr "Искать" - -#: lib/Horde/Mime/Mail.php:458 -#, fuzzy -msgid "Plaintext Version of Message" -msgstr "В теле сообщения" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/sk/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/sk/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index e01418ea7c4..00000000000 Binary files a/lib/horde/locale/sk/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/sk/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/sk/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index e3bb15a9716..00000000000 --- a/lib/horde/locale/sk/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,26 +0,0 @@ -# Slovak translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2011-02-02 16:17+0100\n" -"PO-Revision-Date: 2011-05-18 16:10+0100\n" -"Last-Translator: Martin Matuška \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" - -#: lib/Horde/Exception/NotFound.php:27 -msgid "Not Found" -msgstr "Nenájdené" - -#: lib/Horde/Exception/PermissionDenied.php:27 -msgid "Permission Denied" -msgstr "Prístup odmietnutý" diff --git a/lib/horde/locale/sk/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/sk/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index f3c8f1faa13..00000000000 Binary files a/lib/horde/locale/sk/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/sk/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/sk/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 81d90854c42..00000000000 --- a/lib/horde/locale/sk/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,70 +0,0 @@ -# Slovak translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Martin Matuška , 2011 -# Jozef Sudolský , 2013 -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2012-08-29 13:30+0200\n" -"PO-Revision-Date: 2013-02-01 17:54+0200\n" -"Last-Translator: Jozef Sudolsky \n" -"Language-Team: i18n@lists.horde.org\n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" - -#: lib/Horde/Mime/Mdn.php:188 -msgid "Disposition Notification" -msgstr "Potvrdenie o doručení" - -#: lib/Horde/Mime/Mail.php:419 -msgid "HTML Version of Message" -msgstr "HTML verzia správy" - -#: lib/Horde/Mime/Headers.php:540 -msgid "List-Archive" -msgstr "List-Archive" - -#: lib/Horde/Mime/Headers.php:535 -msgid "List-Help" -msgstr "List-Help" - -#: lib/Horde/Mime/Headers.php:542 -msgid "List-Id" -msgstr "List-Id" - -#: lib/Horde/Mime/Headers.php:538 -msgid "List-Owner" -msgstr "List-Owner" - -#: lib/Horde/Mime/Headers.php:539 -msgid "List-Post" -msgstr "List-Post" - -#: lib/Horde/Mime/Headers.php:537 -msgid "List-Subscribe" -msgstr "List-Subscribe" - -#: lib/Horde/Mime/Headers.php:536 -msgid "List-Unsubscribe" -msgstr "List-Unsubscribe" - -#: lib/Horde/Mime/Mail.php:417 -msgid "Plaintext Version of Message" -msgstr "Verzia správy v čistom texte" - -#: lib/Horde/Mime/Mdn.php:200 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Správa odoslaná dňa %s pre %s s predmetom \"%s\" bola zobrazená.\n" -"\n" -"Neexistuje však záruka, že správa bola prečítaná alebo pochopená." diff --git a/lib/horde/locale/sl/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/sl/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 8705e01d6d2..00000000000 Binary files a/lib/horde/locale/sl/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/sl/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/sl/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 8c86f1c2667..00000000000 --- a/lib/horde/locale/sl/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,27 +0,0 @@ -# Slovenian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" -"%100==4 ? 2 : 3);\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "Ni najden." - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "Dovoljenje je zavrnjeno." diff --git a/lib/horde/locale/sl/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/sl/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 74b94af467c..00000000000 Binary files a/lib/horde/locale/sl/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/sl/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/sl/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 9b288a4354d..00000000000 --- a/lib/horde/locale/sl/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,74 +0,0 @@ -# Slovenian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" -"%100==4 ? 2 : 3);\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Obvestilo o dostavljeni pošti" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Neveljaven naslov naslovnika." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr " Seznam Arhiva " - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "Seznam Pomoči " - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "Seznam Identitet " - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "Seznam Lastnikov " - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "Seznam Pošte " - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "Seznam Prijav " - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "Seznam Odjav " - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Sporočilo poslano dne %s za %s z naslovom \"%s\" je bil prebran.\n" -"\n" -"Ni zagotovila da je bilo dejansko prebrano ali razumljeno." diff --git a/lib/horde/locale/sv/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/sv/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index b8d6164080f..00000000000 Binary files a/lib/horde/locale/sv/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/sv/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/sv/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 81b9624406f..00000000000 --- a/lib/horde/locale/sv/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,27 +0,0 @@ -# Swedish translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "%s saknas." - -#: lib/Horde/Exception/PermissionDenied.php:32 -#, fuzzy -msgid "Permission Denied" -msgstr "Behörighet" diff --git a/lib/horde/locale/sv/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/sv/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 427504f5af3..00000000000 Binary files a/lib/horde/locale/sv/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/sv/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/sv/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 7254ab44d4b..00000000000 --- a/lib/horde/locale/sv/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,72 +0,0 @@ -# Swedish translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Felaktig destinationsadress." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "" - -#: lib/Horde/Mime/Headers.php:514 -#, fuzzy -msgid "List-Help" -msgstr "Visa hjälpämnen" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "" - -#: lib/Horde/Mime/Headers.php:516 -#, fuzzy -msgid "List-Subscribe" -msgstr "Nedsänkt" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" diff --git a/lib/horde/locale/tr/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/tr/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 1b5b2be8089..00000000000 Binary files a/lib/horde/locale/tr/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/tr/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/tr/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index c6f28c27dc3..00000000000 --- a/lib/horde/locale/tr/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,27 +0,0 @@ -# Turkish translations for Horde_Exception module. -# Copyright 2010-2016 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2017-06-09 16:18+0300\n" -"Last-Translator: Automatically generated\n" -"Language-Team: İTÜ BİDB \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: tr\n" -"X-Generator: Poedit 1.8.12\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "Bulunamadı" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "İzin Yok" diff --git a/lib/horde/locale/tr/LC_MESSAGES/Horde_Idna.mo b/lib/horde/locale/tr/LC_MESSAGES/Horde_Idna.mo deleted file mode 100644 index 4d6f96ee2c7..00000000000 Binary files a/lib/horde/locale/tr/LC_MESSAGES/Horde_Idna.mo and /dev/null differ diff --git a/lib/horde/locale/tr/LC_MESSAGES/Horde_Idna.po b/lib/horde/locale/tr/LC_MESSAGES/Horde_Idna.po deleted file mode 100644 index 6dd1766a543..00000000000 --- a/lib/horde/locale/tr/LC_MESSAGES/Horde_Idna.po +++ /dev/null @@ -1,71 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Idna package. -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Idna\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2017-06-09 15:53+0300\n" -"PO-Revision-Date: 2017-06-09 16:18+0300\n" -"Language-Team: İTÜ BİDB \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.12\n" -"Last-Translator: \n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: tr\n" - -#: lib/Horde/Idna.php:83 -msgid "ACE label does not contain a valid label string" -msgstr "ACE etiketi geçerli bir etiket dizesi içermiyor" - -#: lib/Horde/Idna.php:79 -msgid "Contains a dot" -msgstr "Bir nokta içeriyor" - -#: lib/Horde/Idna.php:71 -msgid "Contains disallowed characters" -msgstr "İzin verilmeyen karakterler içeriyor" - -#: lib/Horde/Idna.php:63 -msgid "Contains hyphen in the third and fourth positions" -msgstr "Üçüncü ve dördüncü konumda tire içeriyor" - -#: lib/Horde/Idna.php:87 -msgid "Does not meet the IDNA BiDi requirements (for right-to-left characters)" -msgstr "IDNA BiDi gereksinimlerini karşılamıyor (sağdan sola karakterler için)" - -#: lib/Horde/Idna.php:91 -msgid "Does not meet the IDNA CONTEXTJ requirements" -msgstr "IDNA CONTEXTJ gereksinimlerini karşılamıyor" - -#: lib/Horde/Idna.php:46 -msgid "Domain name is empty" -msgstr "Alan adı boş" - -#: lib/Horde/Idna.php:51 -msgid "Domain name is too long" -msgstr "Alan adı çok uzun" - -#: lib/Horde/Idna.php:59 -msgid "Ends with a hyphen" -msgstr "Tire ile bitiyor" - -#: lib/Horde/Idna.php:75 -msgid "Starts with \"xn--\" but does not contain valid Punycode" -msgstr "\"Xn--\" ile başlıyor ancak geçerli Punycode içermiyor" - -#: lib/Horde/Idna.php:67 -msgid "Starts with a combining mark" -msgstr "Birleştirme işaretiyle başlıyor" - -#: lib/Horde/Idna.php:55 -msgid "Starts with a hyphen" -msgstr "Tire ile başlıyor" - -#: lib/Horde/Idna.php:95 -msgid "Unknown error" -msgstr "Bilinmeyen hata" diff --git a/lib/horde/locale/tr/LC_MESSAGES/Horde_Imap_Client.mo b/lib/horde/locale/tr/LC_MESSAGES/Horde_Imap_Client.mo deleted file mode 100644 index eae6032331e..00000000000 Binary files a/lib/horde/locale/tr/LC_MESSAGES/Horde_Imap_Client.mo and /dev/null differ diff --git a/lib/horde/locale/tr/LC_MESSAGES/Horde_Imap_Client.po b/lib/horde/locale/tr/LC_MESSAGES/Horde_Imap_Client.po deleted file mode 100644 index 167f8f64941..00000000000 --- a/lib/horde/locale/tr/LC_MESSAGES/Horde_Imap_Client.po +++ /dev/null @@ -1,278 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Imap_Client package. -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Imap_Client\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2017-06-09 15:57+0300\n" -"PO-Revision-Date: 2017-06-09 16:19+0300\n" -"Language-Team: İTÜ BİDB \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.12\n" -"Last-Translator: \n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: tr\n" - -#: lib/Horde/Imap/Client/Exception/NoSupportPop3.php:34 -#, php-format -msgid "%s not supported on POP3 servers." -msgstr "%s, POP3 sunucularında desteklenmiyor." - -#: lib/Horde/Imap/Client/Socket.php:5035 -msgid "Authentication credentials have expired." -msgstr "Kimlik doğrulama bilgilerinin süresi doldu." - -#: lib/Horde/Imap/Client/Socket.php:747 lib/Horde/Imap/Client/Socket.php:5019 -#: lib/Horde/Imap/Client/Socket/Pop3.php:441 -#: lib/Horde/Imap/Client/Socket/Pop3.php:460 -#: lib/Horde/Imap/Client/Socket/Pop3.php:486 -#: lib/Horde/Imap/Client/Socket/Pop3.php:498 -msgid "Authentication failed." -msgstr "Kimlik doğrulama başarısız oldu." - -#: lib/Horde/Imap/Client/Auth/DigestMD5.php:158 -#: lib/Horde/Imap/Client/Auth/Scram.php:124 -msgid "Authentication failure." -msgstr "Kimlik doğrulama hatası." - -#: lib/Horde/Imap/Client/Socket.php:5027 -msgid "Authentication was successful, but authorization failed." -msgstr "Kimlik doğrulama başarılıydı ancak yetkilendirme başarısız oldu." - -#: lib/Horde/Imap/Client/Interaction/Server/Tagged.php:44 -msgid "Bad tagged response." -msgstr "Kötü etiketli yanıt." - -#: lib/Horde/Imap/Client/Exception/SearchCharset.php:45 -msgid "Cannot convert search query text to new charset" -msgstr "Arama sorgusu metni yeni karakter setine dönüştürülemez" - -#: lib/Horde/Imap/Client/Base.php:1922 lib/Horde/Imap/Client/Base.php:1985 -msgid "Cannot expunge read-only mailbox." -msgstr "Salt okunur dizini silmek mümkün değil." - -#: lib/Horde/Imap/Client/Socket.php:4811 -msgid "Charset used in search query is not supported on the mail server." -msgstr "" -"Arama sorgusunda kullanılan karakter seti posta sunucusunda desteklenmiyor." - -#: lib/Horde/Imap/Client/Socket.php:1240 -#, php-format -msgid "Could not open mailbox \"%s\"." -msgstr "Dizin \"%s\" açılamadı." - -#: lib/Horde/Imap/Client/Socket.php:358 lib/Horde/Imap/Client/Socket.php:400 -msgid "Could not open secure TLS connection to the IMAP server." -msgstr "IMAP sunucusuna güvenli TLS bağlantısı açılamadı." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:219 -#: lib/Horde/Imap/Client/Socket/Pop3.php:233 -msgid "Could not open secure connection to the POP3 server." -msgstr "POP3 sunucusuna güvenli bağlantı açılamadı." - -#: lib/Horde/Imap/Client/Socket.php:4919 -msgid "Could not save message data because it is too large." -msgstr "İleti verileri çok büyük olduğu için kaydedilemedi." - -#: lib/Horde/Imap/Client/Socket.php:4910 -msgid "Could not save message on server." -msgstr "İleti sunucu üzerinde kaydedilemedi." - -#: lib/Horde/Imap/Client/Socket.php:606 -#: lib/Horde/Imap/Client/Socket/Pop3.php:324 -msgid "Error connecting to mail server." -msgstr "Posta sunucusuna bağlanırken hata oluştu." - -#: lib/Horde/Imap/Client/Utf7imap.php:128 -#: lib/Horde/Imap/Client/Utf7imap.php:156 -#: lib/Horde/Imap/Client/Utf7imap.php:163 -#: lib/Horde/Imap/Client/Utf7imap.php:225 -#: lib/Horde/Imap/Client/Utf7imap.php:245 -#: lib/Horde/Imap/Client/Utf7imap.php:252 -#: lib/Horde/Imap/Client/Utf7imap.php:263 -#: lib/Horde/Imap/Client/Utf7imap.php:272 -msgid "Error converting UTF7-IMAP string." -msgstr "UTF7-IMAP dizesini dönüştürme hatası." - -#: lib/Horde/Imap/Client/Socket.php:4467 -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:83 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:214 -#: lib/Horde/Imap/Client/Socket/Pop3.php:1382 -msgid "Error when communicating with the mail server." -msgstr "Posta sunucusu ile iletişim kurarken hata oluştu." - -#: lib/Horde/Imap/Client/Socket.php:4605 -msgid "IMAP Server closed the connection." -msgstr "IMAP Sunucusu bağlantıyı kapattı." - -#: lib/Horde/Imap/Client/Socket.php:4591 -msgid "IMAP error reported by server." -msgstr "Sunucu tarafından IMAP hatası bildirildi." - -#: lib/Horde/Imap/Client/Socket.php:4009 -#, php-format -msgid "Invalid METADATA entry: \"%s\"." -msgstr "Geçersiz METADATA girişi: \"%s\"." - -#: lib/Horde/Imap/Client/Socket.php:4102 -#, php-format -msgid "Invalid METADATA value type \"%s\"." -msgstr "Geçersiz METADATA değer türü \"%s\"." - -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:148 -msgid "Mail server closed the connection unexpectedly." -msgstr "Posta sunucusu bağlantıyı beklenmedik şekilde kapattı." - -#: lib/Horde/Imap/Client/Socket.php:573 -msgid "Mail server denied authentication." -msgstr "Posta sunucusu kimlik doğrulamayı reddetti." - -#: lib/Horde/Imap/Client/Base.php:2255 lib/Horde/Imap/Client/Base.php:2534 -#: lib/Horde/Imap/Client/Base.php:2806 lib/Horde/Imap/Client/Base.php:2891 -msgid "Mailbox does not support mod-sequences." -msgstr "Dizin mod dizilerini desteklemez." - -#: lib/Horde/Imap/Client/Socket.php:370 -#: lib/Horde/Imap/Client/Socket/Pop3.php:201 -msgid "No password provided." -msgstr "Parola sağlanmadı." - -#: lib/Horde/Imap/Client/Socket.php:498 -msgid "No supported IMAP authentication method could be found." -msgstr "Desteklenen hiçbir IMAP kimlik doğrulama yöntemi bulunamadı." - -#: lib/Horde/Imap/Client/Socket.php:5043 -msgid "Operation failed due to a lack of a secure connection." -msgstr "Güvenli bir bağlantı eksikliği nedeniyle işlem başarısız oldu." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:1448 -msgid "POP3 error reported by server." -msgstr "Sunucu tarafından POP3 hatası bildirildi." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:295 -msgid "POP3 server denied authentication." -msgstr "POP3 sunucusu kimlik doğrulamayı reddetti." - -#: lib/Horde/Imap/Client/Socket.php:5011 -msgid "Remote server is temporarily unavailable." -msgstr "Uzak sunucu geçici olarak kullanılamıyor." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:75 -msgid "Server closed the connection unexpectedly." -msgstr "Sunucu bağlantıyı beklenmedik bir şekilde kapattı." - -#: lib/Horde/Imap/Client/Socket.php:388 -msgid "Server does not support TLS connections." -msgstr "Sunucu TLS bağlantılarını desteklemez." - -#: lib/Horde/Imap/Client/Socket/Pop3.php:219 -msgid "Server does not support secure connections." -msgstr "Sunucu güvenli bağlantıları desteklemez." - -#: lib/Horde/Imap/Client/Socket.php:809 -#: lib/Horde/Imap/Client/Socket/Pop3.php:508 -msgid "Server failed verification check." -msgstr "Sunucu doğrulama kontrolünde başarısız oldu." - -#: lib/Horde/Imap/Client/Socket.php:626 -msgid "Server rejected connection." -msgstr "Sunucu bağlantıyı reddetti." - -#: lib/Horde/Imap/Client/Socket/Connection/Pop3.php:47 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:64 -#: lib/Horde/Imap/Client/Socket/Connection/Socket.php:110 -msgid "Server write error." -msgstr "Sunucu yazma hatası." - -#: lib/Horde/Imap/Client/Socket.php:4964 -msgid "The comparison algorithm was not recognized by the server." -msgstr "Karşılaştırma algoritması sunucu tarafından tanınmadı." - -#: lib/Horde/Imap/Client/Socket.php:635 -msgid "The mail server does not support IMAP4rev1 (RFC 3501)." -msgstr "Posta sunucusu IMAP4rev1 (RFC 3501) desteklemez." - -#: lib/Horde/Imap/Client/Socket.php:5092 -msgid "The mail server has denied the request." -msgstr "Posta sunucusu isteği reddetti." - -#: lib/Horde/Imap/Client/Socket.php:5074 -msgid "The mail server is reporting corrupt data in your mailbox." -msgstr "Posta sunucusu dizininizde bozuk veriler bildiriyor." - -#: lib/Horde/Imap/Client/Socket.php:4876 -msgid "The mail server was unable to parse the contents of the mail message." -msgstr "Posta sunucusu posta iletisinin içeriğini ayrıştıramadı." - -#: lib/Horde/Imap/Client/Socket.php:4827 -#, php-format -msgid "" -"The mail server was unable to parse the contents of the mail message: %s" -msgstr "Posta sunucusu posta iletisinin içeriğini ayrıştıramadı: %s" - -#: lib/Horde/Imap/Client/Socket.php:4982 -msgid "The metadata item could not be saved because it is too large." -msgstr "Metadata veri öğesi çok büyük olduğu için kaydedilemedi." - -#: lib/Horde/Imap/Client/Socket.php:5000 -msgid "" -"The metadata item could not be saved because the maximum number of " -"annotations has been exceeded." -msgstr "" -"En fazla ek açıklama sayısı aşıldığı için meta veri öğesi kaydedilemedi." - -#: lib/Horde/Imap/Client/Socket.php:4991 -msgid "" -"The metadata item could not be saved because the server does not support " -"private annotations." -msgstr "Sunucu özel notları desteklemediği için meta veri öğesi kaydedilemedi." - -#: lib/Horde/Imap/Client/Socket.php:5110 -msgid "The object could not be created because it already exists." -msgstr "Nesne zaten var olduğu için oluşturulamadı." - -#: lib/Horde/Imap/Client/Socket.php:5119 -msgid "The object could not be deleted because it does not exist." -msgstr "Nesne bulunmadığından silinemedi." - -#: lib/Horde/Imap/Client/Socket.php:5101 -msgid "" -"The operation failed because the quota has been exceeded on the mail server." -msgstr "Posta sunucusunda kota aşıldığı için işlem başarısız oldu." - -#: lib/Horde/Imap/Client/Exception/NoSupportExtension.php:46 -#, php-format -msgid "The server does not support the %s extension." -msgstr "Sunucu %s uzantısını desteklemiyor." - -#: lib/Horde/Imap/Client/Socket.php:5128 -msgid "The special-use attribute requested for the mailbox is not supported." -msgstr "Posta kutusu için istenen özel kullanım özelliği desteklenmiyor." - -#: lib/Horde/Imap/Client/Socket.php:5060 -msgid "" -"There was a temporary issue when attempting this operation. Please try again " -"later." -msgstr "" -"Bu işlemi denerken geçici bir sorun oluştu. Lütfen daha sonra tekrar " -"deneyiniz." - -#: lib/Horde/Imap/Client/Socket.php:723 -#: lib/Horde/Imap/Client/Socket/Pop3.php:379 -msgid "Unexpected response from server when authenticating." -msgstr "Kimlik doğrulama işlemi sırasında sunucu tarafından beklenmeyen yanıt." - -#: lib/Horde/Imap/Client/Socket.php:839 -#: lib/Horde/Imap/Client/Socket/Pop3.php:518 -#, php-format -msgid "Unknown authentication method: %s" -msgstr "Bilinmeyen kimlik doğrulama yöntemi: %s" - -#: lib/Horde/Imap/Client/Socket.php:5051 -msgid "You do not have adequate permissions to carry out this operation." -msgstr "Bu işlemi gerçekleştirmek için yeterli izninizin yok." diff --git a/lib/horde/locale/tr/LC_MESSAGES/Horde_Mail.mo b/lib/horde/locale/tr/LC_MESSAGES/Horde_Mail.mo deleted file mode 100644 index 9c35ad389c3..00000000000 Binary files a/lib/horde/locale/tr/LC_MESSAGES/Horde_Mail.mo and /dev/null differ diff --git a/lib/horde/locale/tr/LC_MESSAGES/Horde_Mail.po b/lib/horde/locale/tr/LC_MESSAGES/Horde_Mail.po deleted file mode 100644 index bedb877fe7c..00000000000 --- a/lib/horde/locale/tr/LC_MESSAGES/Horde_Mail.po +++ /dev/null @@ -1,29 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mail package. -# FIRST AUTHOR , YEAR. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mail\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2017-06-09 16:08+0300\n" -"PO-Revision-Date: 2017-06-09 16:20+0300\n" -"Language-Team: İTÜ BİDB \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.12\n" -"Last-Translator: \n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: tr\n" - -#: lib/Horde/Mail/Mbox/Parse.php:65 -msgid "Could not parse mailbox data." -msgstr "Dizin verileri ayrıştırılamadı." - -#: lib/Horde/Mail/Mbox/Parse.php:98 -#, php-format -msgid "Imported mailbox contains more than enforced limit of %u messages." -msgstr "" -"İçeri aktarılan dizin %u iletiden daha fazla zorunlu sınırlar içeriyor." diff --git a/lib/horde/locale/tr/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/tr/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 0852c132db8..00000000000 Binary files a/lib/horde/locale/tr/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/tr/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/tr/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 9717e4f1234..00000000000 --- a/lib/horde/locale/tr/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,75 +0,0 @@ -# Turkish translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2017-06-09 16:20+0300\n" -"Last-Translator: Automatically generated\n" -"Language-Team: İTÜ BİDB \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Language: tr\n" -"X-Generator: Poedit 1.8.12\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Düzen Bildirimi" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "İletinin HTML Sürümü" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Elektronik Posta adresinde geçersiz karakter: %s." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "Listele-Arşiv" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "Listele-Yardım" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "Listele-Id" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "Listele-Sahip" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "Listele-Gönderilmiş Öğeler" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "Listele-Sürdürümcüler" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "Listele-Sürdürümcü Olmayanlar" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "İletinin Düz Metin Sürümü" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"%s de %s e gönderilen \"%s\" konulu ileti görüntülendi.\n" -"\n" -"İletinin okunduğu ve/veya anlaşıldığının garantisi yoktur." diff --git a/lib/horde/locale/uk/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/uk/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 235eba11501..00000000000 Binary files a/lib/horde/locale/uk/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/uk/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/uk/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index 92ec336d707..00000000000 --- a/lib/horde/locale/uk/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,25 +0,0 @@ -# Ukrainian translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2013-04-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: lib/Horde/Exception/NotFound.php:32 -msgid "Not Found" -msgstr "Не знайдено" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "Доступ заборонений" diff --git a/lib/horde/locale/uk/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/uk/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index daff0647660..00000000000 Binary files a/lib/horde/locale/uk/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/uk/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/uk/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 7ec4130fc24..00000000000 --- a/lib/horde/locale/uk/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,73 +0,0 @@ -# Ukrainian translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2013-04-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "Повідомлення про розміщення" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "HTML-версія листа" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "Недозволений символ в адресі е-пошти: %s." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "List-Archive" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "List-Help" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "List-Id" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "List-Owner" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "List-Post" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "List-Subscribe" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "List-Unsubscribe" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "Текстова версія листа" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"Показано лист, відісланий в %s до %s з темою \"%s\".\n" -"Немає гарантії, що лист прочитали та зрозуміли." diff --git a/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index cfa09fd1f3a..00000000000 Binary files a/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index fdc94322ece..00000000000 --- a/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,25 +0,0 @@ -# Chinese translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "未找到。" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "权限不足" diff --git a/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index f3eddc38d83..00000000000 Binary files a/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index df9f1f69244..00000000000 --- a/lib/horde/locale/zh_CN/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,71 +0,0 @@ -# Chinese translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "部署通知" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mail.php:404 -#, fuzzy, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "无效的目的地址。" - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "存档列表" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "帮助列表" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "Id列表" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "所有者列表" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "发布列表" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "订阅列表" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "取消订阅列表" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"已显示 %s 发送给 %s 且主题为“%s”的邮件。\n" -"不保证收件人已阅读或理解此封邮件。" diff --git a/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Exception.mo b/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Exception.mo deleted file mode 100644 index 5062a7c62af..00000000000 Binary files a/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Exception.mo and /dev/null differ diff --git a/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Exception.po b/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Exception.po deleted file mode 100644 index f1bcb61a2de..00000000000 --- a/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Exception.po +++ /dev/null @@ -1,25 +0,0 @@ -# Chinese translations for Horde_Exception module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Exception module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Exception\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Exception/NotFound.php:32 -#, fuzzy -msgid "Not Found" -msgstr "靜音" - -#: lib/Horde/Exception/PermissionDenied.php:32 -msgid "Permission Denied" -msgstr "存取遭拒" diff --git a/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Mime.mo b/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Mime.mo deleted file mode 100644 index 89378f36304..00000000000 Binary files a/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Mime.mo and /dev/null differ diff --git a/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Mime.po b/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Mime.po deleted file mode 100644 index 5329c889ea0..00000000000 --- a/lib/horde/locale/zh_TW/LC_MESSAGES/Horde_Mime.po +++ /dev/null @@ -1,72 +0,0 @@ -# Chinese translations for Horde_Mime module. -# Copyright 2010-2017 Horde LLC (http://www.horde.org/) -# This file is distributed under the same license as the Horde_Mime module. -# Automatically generated, 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Horde_Mime\n" -"Report-Msgid-Bugs-To: dev@lists.horde.org\n" -"POT-Creation-Date: 2010-10-13 01:27+0200\n" -"PO-Revision-Date: 2010-10-13 01:27+0200\n" -"Last-Translator: Automatically generated\n" -"Language-Team: i18n@lists.horde.org\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: lib/Horde/Mime/Mdn.php:202 -msgid "Disposition Notification" -msgstr "傳送回條" - -#: lib/Horde/Mime/Mail.php:460 -msgid "HTML Version of Message" -msgstr "HTML 格式郵件" - -#: lib/Horde/Mime/Mail.php:404 -#, php-format -msgid "Invalid character in e-mail address: %s." -msgstr "電子郵件住址: %s 含有無效的字元." - -#: lib/Horde/Mime/Headers.php:519 -msgid "List-Archive" -msgstr "討論群組-檔案櫃" - -#: lib/Horde/Mime/Headers.php:514 -msgid "List-Help" -msgstr "討論群組-求助" - -#: lib/Horde/Mime/Headers.php:521 -msgid "List-Id" -msgstr "討論群組-識別號碼" - -#: lib/Horde/Mime/Headers.php:517 -msgid "List-Owner" -msgstr "討論群組-擁有者" - -#: lib/Horde/Mime/Headers.php:518 -msgid "List-Post" -msgstr "討論群組-寄件人" - -#: lib/Horde/Mime/Headers.php:516 -msgid "List-Subscribe" -msgstr "討論群組-訂閱" - -#: lib/Horde/Mime/Headers.php:515 -msgid "List-Unsubscribe" -msgstr "討論群組-取消訂閱" - -#: lib/Horde/Mime/Mail.php:458 -msgid "Plaintext Version of Message" -msgstr "純文字格式的郵件" - -#: lib/Horde/Mime/Mdn.php:213 -#, php-format -msgid "" -"The message sent on %s to %s with subject \"%s\" has been displayed.\n" -"\n" -"This is no guarantee that the message has been read or understood." -msgstr "" -"你曾於 %s 寄給 %s 一封主旨為 \"%s\" 的信件已被開啟.\n" -"\n" -"但這並不能保證該信件的內容已完全被收件人看完或了解." diff --git a/lib/horde/readme_moodle.txt b/lib/horde/readme_moodle.txt deleted file mode 100644 index a88a4258f63..00000000000 --- a/lib/horde/readme_moodle.txt +++ /dev/null @@ -1,52 +0,0 @@ -Description of import of Horde libraries -# Clone the Horde Git Tools repository and install. You will need - this for future updates: - https://github.com/horde/git-tools -# Make sure to follow the #Configuration step mentioned in the URL above. In - particular make sure to set the 'git_base' config option in conf.php -# Go into the repository cloned above and perform the following: - bin/horde-git-tools git clone - (Go for a coffee, this will take a while) -# Checkout the latest stable version for all repos, currently 5.2: - bin/horde-git-tools git checkout FRAMEWORK_5_2 -# Copy the following script and store it on /tmp, change it's execute bit(chmod 777), and run it, - passing in your path to Horde (the directory you've cloned the repository): - /tmp/copyhorde.sh ~/git/base/directory/from/step/2 - -Notes: -* 2023-01-20 Applied patch https://github.com/horde/Util/pull/10 -* 2023-01-20 Horde/Mail is copied from https://github.com/bytestream/Mail/tree/v2.7.1 for PHP 8.1 compatibility -* MDL-79890: Calls to array_keys() passing a second parameter have been modified to call `moodle_array_keys_filter` instead for PHP 8.3 compat. - This change is not fed upstream as Horde appears abandoned. - -==== -#!/bin/sh - -source=$1 -target=./lib/horde - -echo "Copy Horde modules from $source to $target" - -modules="Crypt_Blowfish Exception Idna Imap_Client Mail Mime Secret Socket_Client Stream Stream_Filter Stream_Wrapper Support Text_Flowed Translation Util" - -rm -rf $target/locale $target/framework -mkdir -p $target/locale $target/framework/Horde - -for module in $modules -do - echo "Copying $module" - cp -Rf $source/$module/lib/Horde/* $target/framework/Horde - locale=$source/$module/locale - if [ -d $locale ] - then - cp -Rf $locale/* $target/locale - fi -done - -Local modifications: -- lib/Horde/Imap/Client/Exception/ServerResponse.php has been minimally modified for php80 compatibility - The fix applied is already upstream, see https://github.com/horde/Imap_Client/pull/13 and it's available - in Imap_Client 2.30.4 and up. See MDL-73405 for more details. - -Notes: -* 2023-01-30 Applied patch https://github.com/horde/Util/pull/11. See MDL-76412 for more details. diff --git a/lib/tests/messageinbound_test.php b/lib/tests/messageinbound_test.php deleted file mode 100644 index 5b5190f5409..00000000000 --- a/lib/tests/messageinbound_test.php +++ /dev/null @@ -1,175 +0,0 @@ -. - -/** - * Test script for message class. - * - * Test classes for \core\message\inbound. - * - * @package core - * @category test - * @copyright 2015 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace core; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Test script for message class. - * - * Test classes for \core\message\inbound. - * - * @package core - * @category test - * @copyright 2015 Andrew Nicols - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class messageinbound_test extends \advanced_testcase { - - /** - * @dataProvider message_inbound_handler_trim_testprovider - */ - public function test_messageinbound_handler_trim($file, $source, $expectedplain, $expectedhtml) { - $this->resetAfterTest(); - - $mime = \Horde_Mime_Part::parseMessage($source); - if ($plainpartid = $mime->findBody('plain')) { - $messagedata = new \stdClass(); - $messagedata->plain = $mime->getPart($plainpartid)->getContents(); - $messagedata->html = ''; - - list($message, $format) = test_handler::remove_quoted_text($messagedata); - list ($message, $expectedplain) = preg_replace("#\r\n#", "\n", array($message, $expectedplain)); - - // Normalise line endings on both strings. - $this->assertEquals($expectedplain, $message); - $this->assertEquals(FORMAT_PLAIN, $format); - } - - if ($htmlpartid = $mime->findBody('html')) { - $messagedata = new \stdClass(); - $messagedata->plain = ''; - $messagedata->html = $mime->getPart($htmlpartid)->getContents(); - - list($message, $format) = test_handler::remove_quoted_text($messagedata); - - // Normalise line endings on both strings. - list ($message, $expectedhtml) = preg_replace("#\r\n#", "\n", array($message, $expectedhtml)); - $this->assertEquals($expectedhtml, $message); - $this->assertEquals(FORMAT_PLAIN, $format); - } - } - - public function message_inbound_handler_trim_testprovider() { - $fixturesdir = realpath(__DIR__ . '/fixtures/messageinbound/'); - $tests = array(); - $iterator = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator($fixturesdir), - \RecursiveIteratorIterator::LEAVES_ONLY); - - foreach ($iterator as $file) { - if (!preg_match('/\.test$/', $file)) { - continue; - } - - try { - $testdata = $this->read_test_file($file, $fixturesdir); - } catch (\Exception $e) { - die($e->getMessage()); - } - - $test = array( - // The filename. - basename($file), - - $testdata['FULLSOURCE'], - - // The plaintext component of the message. - $testdata['EXPECTEDPLAIN'], - - // The HTML component of the message. - $testdata['EXPECTEDHTML'], - ); - - $tests[basename($file)] = $test; - } - return $tests; - } - - protected function read_test_file(\SplFileInfo $file, $fixturesdir) { - // Break on the --[TOKEN]-- tags in the file. - $content = file_get_contents($file->getRealPath()); - $content = preg_replace("#\r\n#", "\n", $content); - $tokens = preg_split('#(?:^|\n*)----([A-Z]+)----\n#', $content, - -1, PREG_SPLIT_DELIM_CAPTURE); - $sections = array( - // Key => Required. - 'FULLSOURCE' => true, - 'EXPECTEDPLAIN' => true, - 'EXPECTEDHTML' => true, - 'CLIENT' => true, // Required but not needed for tests, just for documentation. - ); - $section = null; - $data = array(); - foreach ($tokens as $i => $token) { - if (null === $section && empty($token)) { - continue; // Skip leading blank. - } - if (null === $section) { - if (!isset($sections[$token])) { - throw new \coding_exception(sprintf( - 'The test file "%s" should not contain a section named "%s".', - basename($file), - $token - )); - } - $section = $token; - continue; - } - $sectiondata = $token; - $data[$section] = $sectiondata; - $section = $sectiondata = null; - } - foreach ($sections as $section => $required) { - if ($required && !isset($data[$section])) { - throw new \coding_exception(sprintf( - 'The test file "%s" must have a section named "%s".', - str_replace($fixturesdir.'/', '', $file), - $section - )); - } - } - return $data; - } -} - -/** - * Class test_handler - */ -class test_handler extends \core\message\inbound\handler { - - public static function remove_quoted_text($messagedata) { - return parent::remove_quoted_text($messagedata); - } - - public function get_name() {} - - public function get_description() {} - - public function process_message(\stdClass $record, \stdClass $messagedata) {} -} diff --git a/lib/thirdpartylibs.xml b/lib/thirdpartylibs.xml index ca8b8a108f6..70ed2b428a2 100644 --- a/lib/thirdpartylibs.xml +++ b/lib/thirdpartylibs.xml @@ -270,19 +270,6 @@ All rights reserved. - - horde - Horde - Library used by the inbound e-mail handling system. - LGPL/BSD - 5.2.23 - 2.1 - https://github.com/horde/base - - Horde LLC - - - requirejs RequireJS diff --git a/lib/upgrade.txt b/lib/upgrade.txt index a5f2a492698..c3d5fccdd1d 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -55,6 +55,8 @@ information provided here is intended especially for developers. * The nocache option for format_text has been removed. It was deprecated in Moodle 2.3. * The set_heading() method has a new parameter, $clean, to define whether the heading should be cleaned or not when no formatting is applied. +* The Horde library has been removed from core. It was only used by the tool_messageinbound. Now tool_messageinbound + uses the new RoundCube library. === 4.3 ===