/** * __construct * * Provide a uid, and parse message structure. * * @param string $uid The message UID. * @param string $folder Folder name * * @see self::$app, self::$storage, self::$opt, self::$parts */ function __construct($uid, $folder = null) { $this->uid = $uid; $this->app = rcube::get_instance(); $this->storage = $this->app->get_storage(); $this->folder = strlen($folder) ? $folder : $this->storage->get_folder(); $this->storage->set_options(array('all_headers' => true)); // Set current folder $this->storage->set_folder($this->folder); $this->headers = $this->storage->get_message($uid); if (!$this->headers) { return; } $this->mime = new rcube_mime($this->headers->charset); $this->subject = $this->mime->decode_mime_string($this->headers->subject); list(, $this->sender) = each($this->mime->decode_address_list($this->headers->from, 1)); $this->set_safe(intval($_GET['_safe']) || $_SESSION['safe_messages'][$uid]); $this->opt = array('safe' => $this->is_safe, 'prefer_html' => $this->app->config->get('prefer_html'), 'get_url' => $this->app->url(array('action' => 'get', 'mbox' => $this->storage->get_folder(), 'uid' => $uid))); if (!empty($this->headers->structure)) { $this->get_mime_numbers($this->headers->structure); $this->parse_structure($this->headers->structure); } else { $this->body = $this->storage->get_body($uid); } // notify plugins and let them analyze this structured message object $this->app->plugins->exec_hook('message_load', array('object' => $this)); }
/** * Get recipients' e-mail addresses * * @return array Recipients' addresses */ public function getRecipients() { // get sender address $headers = $this->message->headers(); $to = rcube_mime::decode_address_list($headers['To'], null, false, null, true); $cc = rcube_mime::decode_address_list($headers['Cc'], null, false, null, true); $bcc = rcube_mime::decode_address_list($headers['Bcc'], null, false, null, true); $recipients = array_unique(array_merge($to, $cc, $bcc)); $recipients = array_diff($recipients, array('undisclosed-recipients:')); return $recipients; }
/** * Test decoding of single e-mail address strings * Uses rcube_mime::decode_address_list() */ function test_decode_single_address() { $headers = array(0 => '*****@*****.**', 1 => '<*****@*****.**>', 2 => 'Test <*****@*****.**>', 3 => 'Test Test <*****@*****.**>', 4 => 'Test Test<*****@*****.**>', 5 => '"Test Test" <*****@*****.**>', 6 => '"Test Test"<*****@*****.**>', 7 => '"Test \\" Test" <*****@*****.**>', 8 => '"Test<Test" <*****@*****.**>', 9 => '=?ISO-8859-1?B?VGVzdAo=?= <*****@*****.**>', 10 => '=?ISO-8859-1?B?VGVzdAo=?=<*****@*****.**>', 11 => 'Test (comment) <*****@*****.**>', 12 => '"Test" (comment) <*****@*****.**>', 13 => '"Test (comment)" (comment) <*****@*****.**>', 14 => '(comment) <*****@*****.**>', 15 => 'Test <test@(comment)domain.tld>', 16 => 'Test Test ((comment)) <*****@*****.**>', 17 => 'test@domain.tld (comment)', 18 => '"Test,Test" <*****@*****.**>', 19 => 'Test <"test test"@domain.tld>', 20 => '<"test test"@domain.tld>', 21 => '"test test"@domain.tld', 22 => '"John Doe @ SomeBusinessName" <MAILER-DAEMON>', 23 => '=?UTF-8?B?IlRlc3QsVGVzdCI=?= <*****@*****.**>', 24 => '"*****@*****.**" <>'); $results = array(0 => array(1, '', '*****@*****.**'), 1 => array(1, '', '*****@*****.**'), 2 => array(1, 'Test', '*****@*****.**'), 3 => array(1, 'Test Test', '*****@*****.**'), 4 => array(1, 'Test Test', '*****@*****.**'), 5 => array(1, 'Test Test', '*****@*****.**'), 6 => array(1, 'Test Test', '*****@*****.**'), 7 => array(1, 'Test " Test', '*****@*****.**'), 8 => array(1, 'Test<Test', '*****@*****.**'), 9 => array(1, 'Test', '*****@*****.**'), 10 => array(1, 'Test', '*****@*****.**'), 11 => array(1, 'Test', '*****@*****.**'), 12 => array(1, 'Test', '*****@*****.**'), 13 => array(1, 'Test (comment)', '*****@*****.**'), 14 => array(1, '', '*****@*****.**'), 15 => array(1, 'Test', '*****@*****.**'), 16 => array(1, 'Test Test', '*****@*****.**'), 17 => array(1, '', '*****@*****.**'), 18 => array(1, 'Test,Test', '*****@*****.**'), 19 => array(1, 'Test', '"test test"@domain.tld'), 20 => array(1, '', '"test test"@domain.tld'), 21 => array(1, '', '"test test"@domain.tld'), 22 => array(1, 'John Doe @ SomeBusinessName', 'MAILER-DAEMON'), 23 => array(1, 'Test,Test', '*****@*****.**'), 24 => array(1, '', '*****@*****.**')); foreach ($headers as $idx => $header) { $res = rcube_mime::decode_address_list($header); $this->assertEquals($results[$idx][0], count($res), "Rows number in result for header: " . $header); $this->assertEquals($results[$idx][1], $res[1]['name'], "Name part decoding for header: " . $header); $this->assertEquals($results[$idx][2], $res[1]['mailto'], "Email part decoding for header: " . $header); } }
/** * __construct * * Provide a uid, and parse message structure. * * @param string $uid The message UID. * @param string $folder Folder name * @param bool $is_safe Security flag * * @see self::$app, self::$storage, self::$opt, self::$parts */ function __construct($uid, $folder = null, $is_safe = false) { // decode combined UID-folder identifier if (preg_match('/^[0-9.]+-.+/', $uid)) { list($uid, $folder) = explode('-', $uid, 2); } if (preg_match('/^([0-9]+)\\.([0-9.]+)$/', $uid, $matches)) { $uid = $matches[1]; $context = $matches[2]; } $this->uid = $uid; $this->context = $context; $this->app = rcube::get_instance(); $this->storage = $this->app->get_storage(); $this->folder = strlen($folder) ? $folder : $this->storage->get_folder(); // Set current folder $this->storage->set_folder($this->folder); $this->storage->set_options(array('all_headers' => true)); $this->headers = $this->storage->get_message($uid); if (!$this->headers) { return; } $this->set_safe($is_safe || $_SESSION['safe_messages'][$this->folder . ':' . $uid]); $this->opt = array('safe' => $this->is_safe, 'prefer_html' => $this->app->config->get('prefer_html'), 'get_url' => $this->app->url(array('action' => 'get', 'mbox' => $this->folder, 'uid' => $uid), false, false, true)); if (!empty($this->headers->structure)) { $this->get_mime_numbers($this->headers->structure); $this->parse_structure($this->headers->structure); } else { if ($this->context === null) { $this->body = $this->storage->get_body($uid); } } $this->mime = new rcube_mime($this->headers->charset); $this->subject = $this->headers->get('subject'); list(, $this->sender) = each($this->mime->decode_address_list($this->headers->from, 1)); // notify plugins and let them analyze this structured message object $this->app->plugins->exec_hook('message_load', array('object' => $this)); }
/** * Add mobile_text in messages list * * @param array $args * @return array */ public function messages_list($args) { if (isset($args['messages'])) { foreach ($args['messages'] as $message) { $address = rcube_mime::decode_address_list($message->from, null, true); $from = "NNN"; if (isset($address[1])) { if (isset($address[1]['name'])) { $from = $address[1]['name']; } elseif (isset($address[1]['mailto'])) { $from = $address[1]['mailto']; } } // Remove specials chars $from = str_replace(array(' ', '~', '"', "'", '!', '>'), '', $from); $from = strtoupper($from); $message->mobile_text = substr($from, 0, 3); $message->mobile_class = $this->get_mobile_class($message->mobile_text); } } return $args; }
/** * Send the given message using the configured method. * * @param object $message Reference to Mail_MIME object * @param string $from Sender address string * @param array $mailto Array of recipient address strings * @param array $error SMTP error array (reference) * @param string $body_file Location of file with saved message body (reference), * used when delay_file_io is enabled * @param array $options SMTP options (e.g. DSN request) * * @return boolean Send status. */ public function deliver_message(&$message, $from, $mailto, &$error, &$body_file = null, $options = null) { $plugin = $this->plugins->exec_hook('message_before_send', array('message' => $message, 'from' => $from, 'mailto' => $mailto, 'options' => $options)); if ($plugin['abort']) { if (!empty($plugin['error'])) { $error = $plugin['error']; } if (!empty($plugin['body_file'])) { $body_file = $plugin['body_file']; } return isset($plugin['result']) ? $plugin['result'] : false; } $from = $plugin['from']; $mailto = $plugin['mailto']; $options = $plugin['options']; $message = $plugin['message']; $headers = $message->headers(); // send thru SMTP server using custom SMTP library if ($this->config->get('smtp_server')) { // generate list of recipients $a_recipients = (array) $mailto; if (strlen($headers['Cc'])) { $a_recipients[] = $headers['Cc']; } if (strlen($headers['Bcc'])) { $a_recipients[] = $headers['Bcc']; } // clean Bcc from header for recipients $send_headers = $headers; unset($send_headers['Bcc']); // here too, it because txtHeaders() below use $message->_headers not only $send_headers unset($message->_headers['Bcc']); $smtp_headers = $message->txtHeaders($send_headers, true); if ($message->getParam('delay_file_io')) { // use common temp dir $temp_dir = $this->config->get('temp_dir'); $body_file = tempnam($temp_dir, 'rcmMsg'); if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) { self::raise_error(array('code' => 650, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Could not create message: " . $mime_result->getMessage()), TRUE, FALSE); return false; } $msg_body = fopen($body_file, 'r'); } else { $msg_body = $message->get(); } // send message if (!is_object($this->smtp)) { $this->smtp_init(true); } $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $options); $response = $this->smtp->get_response(); $error = $this->smtp->get_error(); // log error if (!$sent) { self::raise_error(array('code' => 800, 'type' => 'smtp', 'line' => __LINE__, 'file' => __FILE__, 'message' => join("\n", $response)), true, false); } } else { // unset some headers because they will be added by the mail() function $headers_enc = $message->headers($headers); $headers_php = $message->_headers; unset($headers_php['To'], $headers_php['Subject']); // reset stored headers and overwrite $message->_headers = array(); $header_str = $message->txtHeaders($headers_php); // #1485779 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) { $headers_enc['To'] = implode(', ', $m[1]); } } $msg_body = $message->get(); if (PEAR::isError($msg_body)) { self::raise_error(array('code' => 650, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Could not create message: " . $msg_body->getMessage()), TRUE, FALSE); } else { $delim = $this->config->header_delimiter(); $to = $headers_enc['To']; $subject = $headers_enc['Subject']; $header_str = rtrim($header_str); if ($delim != "\r\n") { $header_str = str_replace("\r\n", $delim, $header_str); $msg_body = str_replace("\r\n", $delim, $msg_body); $to = str_replace("\r\n", $delim, $to); $subject = str_replace("\r\n", $delim, $subject); } if (filter_var(ini_get('safe_mode'), FILTER_VALIDATE_BOOLEAN)) { $sent = mail($to, $subject, $msg_body, $header_str); } else { $sent = mail($to, $subject, $msg_body, $header_str, "-f{$from}"); } } } if ($sent) { $this->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body)); // remove MDN headers after sending unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']); if ($this->config->get('smtp_log')) { // get all recipient addresses if (is_array($mailto)) { $mailto = implode(',', $mailto); } if ($headers['Cc']) { $mailto .= ',' . $headers['Cc']; } if ($headers['Bcc']) { $mailto .= ',' . $headers['Bcc']; } $mailto = rcube_mime::decode_address_list($mailto, null, false, null, true); self::write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s", $this->user->get_username(), rcube_utils::remote_addr(), implode(', ', $mailto), !empty($response) ? join('; ', $response) : '')); } } else { // allow plugins to catch sending errors with the same parameters as in 'message_before_send' $this->plugins->exec_hook('message_send_error', $plugin + array('error' => $error)); } if (is_resource($msg_body)) { fclose($msg_body); } $message->_headers = array(); $message->headers($headers); return $sent; }
/** * Collect the email address of a just-sent email recipients into * the automatic addressbook (if it's not already in another * addressbook). */ public function register_recipients($p) { $rcmail = rcmail::get_instance(); if (!$rcmail->config->get('use_auto_abook', true)) { return; } $headers = $p['headers']; if (!class_exists('rcube_mime')) { // RC < 0.8 compatibility code $IMAP = new rcube_imap(null); $all_recipients = array_merge($IMAP->decode_address_list($headers['To'], null, true, $headers['charset']), $IMAP->decode_address_list($headers['Cc'], null, true, $headers['charset']), $IMAP->decode_address_list($headers['Bcc'], null, true, $headers['charset'])); } else { $all_recipients = array_merge(rcube_mime::decode_address_list($headers['To'], null, true, $headers['charset']), rcube_mime::decode_address_list($headers['Cc'], null, true, $headers['charset']), rcube_mime::decode_address_list($headers['Bcc'], null, true, $headers['charset'])); } require_once dirname(__FILE__) . '/automatic_addressbook_backend.php'; $CONTACTS = new automatic_addressbook_backend($rcmail->db, $rcmail->user->ID); foreach ($all_recipients as $recipient) { // Bcc and Cc can be empty if ($recipient['mailto'] != '') { $contact = array('email' => $recipient['mailto'], 'name' => $recipient['name']); // use email address part for name if (empty($contact['name']) || $contact['name'] == $contact['email']) { $contact['name'] = ucfirst(preg_replace('/[\\.\\-]/', ' ', substr($contact['email'], 0, strpos($contact['email'], '@')))); } /* We only want to add the contact to the collected contacts * address book if it is not already in an addressbook, so we * first lookup in every address source. */ $book_types = (array) $rcmail->config->get('autocomplete_addressbooks', 'sql'); foreach ($book_types as $id) { $abook = $rcmail->get_address_book($id); $previous_entries = $abook->search('email', $contact['email'], false, false); if ($previous_entries->count) { break; } } if (!$previous_entries->count) { $plugin = $rcmail->plugins->exec_hook('contact_create', array('record' => $contact, 'source' => $this->abook_id)); if (!$plugin['abort']) { $CONTACTS->insert($contact, false); } } } } }
/** * Extract mail headers for new filter form */ private function parse_headers($headers) { $result = array(); if ($headers->subject) { $result[] = array('Subject', rcube_mime::decode_header($headers->subject)); } // @TODO: List-Id, others? foreach (array('From', 'To') as $h) { $hl = strtolower($h); if ($headers->{$hl}) { $list = rcube_mime::decode_address_list($headers->{$hl}); foreach ($list as $item) { if ($item['mailto']) { $result[] = array($h, $item['mailto']); } } } } return $result; }
/** * Server-side key pair generation handler */ private function key_generate() { $user = rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST, true); $pass = rcube_utils::get_input_value('_password', rcube_utils::INPUT_POST, true); $size = (int) rcube_utils::get_input_value('_size', rcube_utils::INPUT_POST); if ($size > 4096) { $size = 4096; } $ident = rcube_mime::decode_address_list($user, 1, false); if (empty($ident)) { $this->rc->output->show_message('enigma.keygenerateerror', 'error'); $this->rc->output->send(); } $this->enigma->load_engine(); $result = $this->enigma->engine->generate_key(array('user' => $ident[1]['name'], 'email' => $ident[1]['mailto'], 'password' => $pass, 'size' => $size)); if ($result instanceof enigma_key) { $this->rc->output->command('enigma_key_create_success'); $this->rc->output->show_message('enigma.keygeneratesuccess', 'confirmation'); } else { $this->rc->output->show_message('enigma.keygenerateerror', 'error'); } $this->rc->output->send(); }
/** * Handler for POST request to import an event attached to a mail message */ public function mail_import_itip() { $uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST); $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST); $mime_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_POST); $status = rcube_utils::get_input_value('_status', rcube_utils::INPUT_POST); $delete = intval(rcube_utils::get_input_value('_del', rcube_utils::INPUT_POST)); $noreply = intval(rcube_utils::get_input_value('_noreply', rcube_utils::INPUT_POST)) || $status == 'needs-action'; $error_msg = $this->gettext('errorimportingtask'); $success = false; $delegate = null; if ($status == 'delegated') { $delegates = rcube_mime::decode_address_list(rcube_utils::get_input_value('_to', rcube_utils::INPUT_POST, true), 1, false); $delegate = reset($delegates); if (empty($delegate) || empty($delegate['mailto'])) { $this->rc->output->command('display_message', $this->gettext('libcalendaring.delegateinvalidaddress'), 'error'); return; } } // successfully parsed tasks? if ($task = $this->lib->mail_get_itip_object($mbox, $uid, $mime_id, 'task')) { $task = $this->from_ical($task); // forward iTip request to delegatee if ($delegate) { $rsvpme = intval(rcube_utils::get_input_value('_rsvp', rcube_utils::INPUT_POST)); $itip = $this->load_itip(); if ($itip->delegate_to($task, $delegate, $rsvpme ? true : false)) { $this->rc->output->show_message('tasklist.itipsendsuccess', 'confirmation'); } else { $this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error'); } } // find writeable list to store the task $list_id = !empty($_REQUEST['_folder']) ? rcube_utils::get_input_value('_folder', rcube_utils::INPUT_POST) : null; $lists = $this->driver->get_lists(); $list = $lists[$list_id]; $dontsave = $_REQUEST['_folder'] === '' && $task['_method'] == 'REQUEST'; // select default list except user explicitly selected 'none' if (!$list && !$dontsave) { $list = $this->get_default_tasklist($task['sensitivity']); } $metadata = array('uid' => $task['uid'], 'changed' => is_object($task['changed']) ? $task['changed']->format('U') : 0, 'sequence' => intval($task['sequence']), 'fallback' => strtoupper($status), 'method' => $task['_method'], 'task' => 'tasks'); // update my attendee status according to submitted method if (!empty($status)) { $organizer = $task['organizer']; $emails = $this->lib->get_user_emails(); foreach ($task['attendees'] as $i => $attendee) { if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { $metadata['attendee'] = $attendee['email']; $metadata['rsvp'] = $attendee['role'] != 'NON-PARTICIPANT'; $reply_sender = $attendee['email']; $task['attendees'][$i]['status'] = strtoupper($status); if (!in_array($task['attendees'][$i]['status'], array('NEEDS-ACTION', 'DELEGATED'))) { $task['attendees'][$i]['rsvp'] = false; // unset RSVP attribute } } } // add attendee with this user's default identity if not listed if (!$reply_sender) { $sender_identity = $this->rc->user->list_emails(true); $task['attendees'][] = array('name' => $sender_identity['name'], 'email' => $sender_identity['email'], 'role' => 'OPT-PARTICIPANT', 'status' => strtoupper($status)); $metadata['attendee'] = $sender_identity['email']; } } // save to tasklist if ($list && $list['editable']) { $task['list'] = $list['id']; // check for existing task with the same UID $existing = $this->driver->get_task($task['uid']); if ($existing) { // only update attendee status if ($task['_method'] == 'REPLY') { // try to identify the attendee using the email sender address $existing_attendee = -1; $existing_attendee_emails = array(); foreach ($existing['attendees'] as $i => $attendee) { $existing_attendee_emails[] = $attendee['email']; if ($task['_sender'] && ($attendee['email'] == $task['_sender'] || $attendee['email'] == $task['_sender_utf'])) { $existing_attendee = $i; } } $task_attendee = null; foreach ($task['attendees'] as $attendee) { if ($task['_sender'] && ($attendee['email'] == $task['_sender'] || $attendee['email'] == $task['_sender_utf'])) { $task_attendee = $attendee; $metadata['fallback'] = $attendee['status']; $metadata['attendee'] = $attendee['email']; $metadata['rsvp'] = $attendee['rsvp'] || $attendee['role'] != 'NON-PARTICIPANT'; if ($attendee['status'] != 'DELEGATED') { break; } } else { if (!empty($attendee['delegated-from']) && (stripos($attendee['delegated-from'], $task['_sender']) !== false || stripos($attendee['delegated-from'], $task['_sender_utf']) !== false) && !in_array($attendee['email'], $existing_attendee_emails)) { $existing['attendees'][] = $attendee; } } } // if delegatee has declined, set delegator's RSVP=True if ($task_attendee && $task_attendee['status'] == 'DECLINED' && $task_attendee['delegated-from']) { foreach ($existing['attendees'] as $i => $attendee) { if ($attendee['email'] == $task_attendee['delegated-from']) { $existing['attendees'][$i]['rsvp'] = true; break; } } } // found matching attendee entry in both existing and new events if ($existing_attendee >= 0 && $task_attendee) { $existing['attendees'][$existing_attendee] = $task_attendee; $success = $this->driver->edit_task($existing); } else { if (($task['sequence'] >= $existing['sequence'] || $task['changed'] >= $existing['changed']) && $task_attendee) { $existing['attendees'][] = $task_attendee; $success = $this->driver->edit_task($existing); } else { $error_msg = $this->gettext('newerversionexists'); } } } else { if ($status == 'declined' && $delete) { $deleted = $this->driver->delete_task($existing, true); $success = true; } else { if ($task['sequence'] >= $existing['sequence'] || $task['changed'] >= $existing['changed']) { $task['id'] = $existing['id']; $task['list'] = $existing['list']; // preserve my participant status for regular updates if (empty($status)) { $emails = $this->lib->get_user_emails(); foreach ($task['attendees'] as $i => $attendee) { if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { foreach ($existing['attendees'] as $j => $_attendee) { if ($attendee['email'] == $_attendee['email']) { $task['attendees'][$i] = $existing['attendees'][$j]; break; } } } } } // set status=CANCELLED on CANCEL messages if ($task['_method'] == 'CANCEL') { $task['status'] = 'CANCELLED'; } // show me as free when declined (#1670) if ($status == 'declined' || $task['status'] == 'CANCELLED') { $task['free_busy'] = 'free'; } $success = $this->driver->edit_task($task); } else { if (!empty($status)) { $existing['attendees'] = $task['attendees']; if ($status == 'declined') { // show me as free when declined (#1670) $existing['free_busy'] = 'free'; } $success = $this->driver->edit_event($existing); } else { $error_msg = $this->gettext('newerversionexists'); } } } } } else { if (!$existing && ($status != 'declined' || $this->rc->config->get('kolab_invitation_tasklists'))) { $success = $this->driver->create_task($task); } else { if ($status == 'declined') { $error_msg = null; } } } } else { if ($status == 'declined' || $dontsave) { $error_msg = null; } else { $error_msg = $this->gettext('nowritetasklistfound'); } } } if ($success || $dontsave) { if ($success) { $message = $task['_method'] == 'REPLY' ? 'attendeupdateesuccess' : ($deleted ? 'successremoval' : ($existing ? 'updatedsuccessfully' : 'importedsuccessfully')); $this->rc->output->command('display_message', $this->gettext(array('name' => $message, 'vars' => array('list' => $list['name']))), 'confirmation'); } $metadata['rsvp'] = intval($metadata['rsvp']); $metadata['after_action'] = $this->rc->config->get('calendar_itip_after_action', 0); $this->rc->output->command('plugin.itip_message_processed', $metadata); $error_msg = null; } else { if ($error_msg) { $this->rc->output->command('display_message', $error_msg, 'error'); } } // send iTip reply if ($task['_method'] == 'REQUEST' && $organizer && !$noreply && !in_array(strtolower($organizer['email']), $emails) && !$error_msg) { $task['comment'] = rcube_utils::get_input_value('_comment', rcube_utils::INPUT_POST); $itip = $this->load_itip(); $itip->set_sender_email($reply_sender); if ($itip->send_itip_message($this->to_libcal($task), 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status)) { $this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $organizer['name'] ?: $organizer['email']))), 'confirmation'); } else { $this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error'); } } $this->rc->output->send(); }
function create_rule($args) { $rcmail = rcube::get_instance(); if ($rcmail->action == 'plugin.sieverules.add' || $rcmail->action == 'plugin.sieverules.edit') { $messageset = unserialize($_SESSION['plugin.sieverules.messageset']); $headers = $args['defaults']['headers']; $rcmail->storage_init(); $use_address = preg_match('/^address::/', $this->headers[1]['value']) ? true : false; foreach ($messageset as $mbox => $uids) { $rcmail->get_storage()->set_folder($mbox); foreach ($uids as $uid) { $message = new rcube_message($uid); $this->_add_to_array($args['script']['tests'], array('type' => $use_address ? 'address' : 'header', 'operator' => 'is', 'header' => 'From', 'target' => $message->sender['mailto'])); $recipients = array(); $recipients_array = rcube_mime::decode_address_list($message->headers->to); foreach ($recipients_array as $recipient) { $recipients[] = $recipient['mailto']; } $identity = $rcmail->user->get_identity(); $recipient_str = join(', ', $recipients); if ($recipient_str != $identity['email']) { $this->_add_to_array($args['script']['tests'], array('type' => $use_address ? 'address' : 'header', 'operator' => 'is', 'header' => 'To', 'target' => $recipient_str)); } if (strlen($message->subject) > 0) { $this->_add_to_array($args['script']['tests'], array('type' => 'header', 'operator' => 'contains', 'header' => 'Subject', 'target' => $message->subject)); } foreach ($this->additional_headers as $header) { if (strlen($message->headers->others[strtolower($header)]) > 0) { $this->_add_to_array($args['script']['tests'], array('type' => 'header', 'operator' => 'is', 'header' => $header, 'target' => $message->headers->others[strtolower($header)])); } } $this->_add_to_array($args['script']['actions'], array('type' => 'fileinto', 'target' => $mbox)); foreach ($message->headers->flags as $flag => $value) { if ($flag == 'FLAGGED') { $this->_add_to_array($args['script']['actions'], array('type' => 'imapflags', 'target' => '\\\\Flagged')); } } } } $_SESSION['plugin.sieverules.rule'] = false; $_SESSION['plugin.sieverules.messageset'] = null; } return $args; }
/** * Forward the given iTip event as delegation to another person * * @param array Event object to delegate * @param mixed Delegatee as string or hash array with keys 'name' and 'mailto' * @param boolean The delegator's RSVP flag * @param array List with indexes of new/updated attendees * @return boolean True on success, False on failure */ public function delegate_to(&$event, $delegate, $rsvp = false, &$attendees = array()) { if (is_string($delegate)) { $delegates = rcube_mime::decode_address_list($delegate, 1, false); if (count($delegates) > 0) { $delegate = reset($delegates); } } $emails = $this->lib->get_user_emails(); $me = $this->rc->user->list_emails(true); // find/create the delegate attendee $delegate_attendee = array('email' => $delegate['mailto'], 'name' => $delegate['name'], 'role' => 'REQ-PARTICIPANT'); $delegate_index = count($event['attendees']); foreach ($event['attendees'] as $i => $attendee) { // set myself the DELEGATED-TO parameter if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { $event['attendees'][$i]['delegated-to'] = $delegate['mailto']; $event['attendees'][$i]['status'] = 'DELEGATED'; $event['attendees'][$i]['role'] = 'NON-PARTICIPANT'; $event['attendees'][$i]['rsvp'] = $rsvp; $me['email'] = $attendee['email']; $delegate_attendee['role'] = $attendee['role']; } else { if (stripos($delegate['mailto'], $attendee['email']) !== false && $attendee['role'] != 'ORGANIZER') { $delegate_attendee = $attendee; $delegate_index = $i; break; } } // TODO: remove previous delegatee (i.e. attendee that has DELEGATED-FROM == $me) } // set/add delegate attendee with RSVP=TRUE and DELEGATED-FROM parameter $delegate_attendee['rsvp'] = true; $delegate_attendee['status'] = 'NEEDS-ACTION'; $delegate_attendee['delegated-from'] = $me['email']; $event['attendees'][$delegate_index] = $delegate_attendee; $attendees[] = $delegate_index; $this->set_sender_email($me['email']); return $this->send_itip_message($event, 'REQUEST', $delegate_attendee, 'itipsubjectdelegatedto', 'itipmailbodydelegatedto'); }
/** * Send the given message using the configured method. * * @param object $message Reference to Mail_MIME object * @param string $from Sender address string * @param array $mailto Array of recipient address strings * @param array $error SMTP error array (reference) * @param string $body_file Location of file with saved message body (reference), * used when delay_file_io is enabled * @param array $options SMTP options (e.g. DSN request) * @param bool $disconnect Close SMTP connection ASAP * * @return boolean Send status. */ public function deliver_message(&$message, $from, $mailto, &$error, &$body_file = null, $options = null, $disconnect = false) { $plugin = $this->plugins->exec_hook('message_before_send', array('message' => $message, 'from' => $from, 'mailto' => $mailto, 'options' => $options)); if ($plugin['abort']) { if (!empty($plugin['error'])) { $error = $plugin['error']; } if (!empty($plugin['body_file'])) { $body_file = $plugin['body_file']; } return isset($plugin['result']) ? $plugin['result'] : false; } $from = $plugin['from']; $mailto = $plugin['mailto']; $options = $plugin['options']; $message = $plugin['message']; $headers = $message->headers(); // generate list of recipients $a_recipients = (array) $mailto; if (strlen($headers['Cc'])) { $a_recipients[] = $headers['Cc']; } if (strlen($headers['Bcc'])) { $a_recipients[] = $headers['Bcc']; } // remove Bcc header and get the whole head of the message as string $smtp_headers = $message->txtHeaders(array('Bcc' => null), true); if ($message->getParam('delay_file_io')) { // use common temp dir $temp_dir = $this->config->get('temp_dir'); $body_file = tempnam($temp_dir, 'rcmMsg'); $mime_result = $message->saveMessageBody($body_file); if (is_a($mime_result, 'PEAR_Error')) { self::raise_error(array('code' => 650, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Could not create message: " . $mime_result->getMessage()), true, false); return false; } $msg_body = fopen($body_file, 'r'); } else { $msg_body = $message->get(); } // initialize SMTP connection if (!is_object($this->smtp)) { $this->smtp_init(true); } // send message $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $options); $response = $this->smtp->get_response(); $error = $this->smtp->get_error(); if (!$sent) { self::raise_error(array('code' => 800, 'type' => 'smtp', 'line' => __LINE__, 'file' => __FILE__, 'message' => join("\n", $response)), true, false); // allow plugins to catch sending errors with the same parameters as in 'message_before_send' $this->plugins->exec_hook('message_send_error', $plugin + array('error' => $error)); } else { $this->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body)); // remove MDN headers after sending unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']); if ($this->config->get('smtp_log')) { // get all recipient addresses $mailto = implode(',', $a_recipients); $mailto = rcube_mime::decode_address_list($mailto, null, false, null, true); self::write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s", $this->user->get_username(), rcube_utils::remote_addr(), implode(', ', $mailto), !empty($response) ? join('; ', $response) : '')); } } if (is_resource($msg_body)) { fclose($msg_body); } if ($disconnect) { $this->smtp->disconnect(); } $message->headers($headers, true); return $sent; }
/** * Handler for attaching public key to a message * * @param Mail_mime Original message * * @return bool True on success, False on failure */ function attach_public_key(&$message) { $headers = $message->headers(); $from = rcube_mime::decode_address_list($headers['From'], 1, false, null, true); $from = $from[1]; // find my key if ($from && ($key = $this->find_key($from))) { $pubkey_armor = $this->export_key($key->id); if (!$pubkey_armor instanceof enigma_error) { $pubkey_name = '0x' . enigma_key::format_id($key->id) . '.asc'; $message->addAttachment($pubkey_armor, 'application/pgp-keys', $pubkey_name, false, '7bit'); return true; } } return false; }
public function message_compose($params) { global $IMAP; global $USER; $this->load_config(); $address = null; $rcmail = rcmail::get_instance(); if (isset($params['param']['reply_uid'])) { $message = $params['param']['reply_uid']; } else { if (isset($params['param']['forward_uid'])) { $message = $params['param']['forward_uid']; } else { if (isset($params['param']['uid'])) { $message = $params['param']['uid']; } else { $message = null; } } } if ($rcmail->config->get('custom_from_compose_auto', true) && $message !== null) { // Newer versions of roundcube don't provide a global $IMAP or $USER variable if (!isset($IMAP) && isset($rcmail->storage)) { $IMAP = $rcmail->storage; } if (!isset($USER) && isset($rcmail->user)) { $USER = $rcmail->user; } $IMAP->get_all_headers = true; $headers = $IMAP->get_message($message); if ($headers !== null) { // Browse headers where addresses will be fetched from $recipients = array(); $rules = $this->parse_headers($rcmail->config->get('custom_from_header_rules', self::HEADER_RULES)); foreach ($rules as $header => $rule) { // RC < 0.8 compatibility code if (!class_exists('rcube_mime')) { if (in_array($header, self::$default_headers)) { $addresses = isset($headers->{$header}) ? $IMAP->decode_address_list($headers->{$header}) : array(); } else { $addresses = isset($headers->others[$header]) ? $IMAP->decode_address_list($headers->others[$header]) : array(); } } else { if (in_array($header, self::$default_headers)) { $addresses = isset($headers->{$header}) ? rcube_mime::decode_address_list($headers->{$header}) : array(); } else { $addresses = isset($headers->others[$header]) ? rcube_mime::decode_address_list($headers->others[$header]) : array(); } } // Decode recipients and matching rules from retrieved addresses foreach ($addresses as $address) { if (isset($address['mailto'])) { $email = $address['mailto']; $recipients[] = array('domain' => preg_replace('/^[^@]*@(.*)$/', '$1', $email), 'email' => $email, 'match_domain' => strpos($rule, 'd') !== false, 'match_exact' => strpos($rule, 'e') !== false, 'match_other' => strpos($rule, 'o') !== false, 'name' => $address['name']); } } } // Get user identities list $identities = array(); foreach ($USER->list_identities() as $identity) { $identities[$identity['email']] = array('domain' => preg_replace('/^[^@]*@(.*)$/', '$1', $identity['email']), 'name' => $identity['name']); } // Find best possible match from recipients and identities $address = null; $score = 0; foreach ($recipients as $recipient) { $email = $recipient['email']; // Relevance score 3: exact match found in identities if ($score < 3 && $recipient['match_exact'] && isset($identities[$email])) { $address = null; $score = 3; } // Relevance score 2: domain match found in identities if ($score < 2 && $recipient['match_domain']) { foreach ($identities as $identity) { if (strcasecmp($identity['domain'], $recipient['domain']) == 0) { $address = $identity['name'] ? $identity['name'] . ' <' . $email . '>' : $email; $score = 2; } } } // Relevance score 1: no match found if ($score < 1 && $recipient['match_other']) { $address = $recipient['name'] ? $recipient['name'] . ' <' . $email . '>' : $email; $score = 1; } } } } $_SESSION['custom_from'] = $address; }
/** * Helper method to packs all the given messages into a zip archive * * @param array List of message UIDs to download */ private function _download_messages($messageset) { $rcmail = rcmail::get_instance(); $imap = $rcmail->get_storage(); $mode = rcube_utils::get_input_value('_mode', rcube_utils::INPUT_POST); $temp_dir = $rcmail->config->get('temp_dir'); $tmpfname = tempnam($temp_dir, 'zipdownload'); $tempfiles = array($tmpfname); $folders = count($messageset) > 1; // @TODO: file size limit // open zip file $zip = new ZipArchive(); $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE); if ($mode == 'mbox') { $tmpfp = fopen($tmpfname . '.mbox', 'w'); } $start = time(); if (!is_array($_SESSION['zipdownload_uids'])) { $_SESSION['zipdownload_uids'] = array(); } $count = 0; foreach ($messageset as $mbox => $uids) { $imap->set_folder($mbox); $path = $folders ? str_replace($imap->get_hierarchy_delimiter(), '/', $mbox) . '/' : ''; if ($uids === '*') { $index = $imap->index($mbox, null, null, true); $uids = $index->get(); } foreach ($uids as $uid) { if (isset($_SESSION['zipdownload_uids'][$mbox . '|' . $uid])) { continue; } $count++; $headers = $imap->get_message_headers($uid); if ($mode == 'mbox') { $from = rcube_mime::decode_address_list($headers->from, null, true, $headers->charset, true); $from = array_shift($from); // Mbox format header // @FIXME: \r\n or \n // @FIXME: date format $header = sprintf("From %s %s\r\n", $from ? preg_replace('/\\s/', '-', $from) : 'MAILER-DAEMON', $headers->internaldate); fwrite($tmpfp, $header); // Use stream filter to quote "From " in the message body stream_filter_register('mbox_filter', '_zipdownload_mbox_filter'); $filter = stream_filter_append($tmpfp, 'mbox_filter'); $imap->get_raw_body($uid, $tmpfp); stream_filter_remove($filter); fwrite($tmpfp, "\r\n"); } else { // maildir $subject = rcube_mime::decode_mime_string((string) $headers->subject); $subject = $this->_convert_filename($subject); $subject = substr($subject, 0, 16); $disp_name = ($subject ? $subject : 'message_rfc822') . ".eml"; $disp_name = $path . $uid . "_" . $disp_name; $tmpfn = tempnam($temp_dir, 'zipmessage'); $tmpfp = fopen($tmpfn, 'w'); $imap->get_raw_body($uid, $tmpfp); $tempfiles[] = $tmpfn; fclose($tmpfp); $zip->addFile($tmpfn, $disp_name); } $_SESSION['zipdownload_uids'][$mbox . '|' . $uid] = 1; if ($to = $rcmail->config->get('zipdownload_resume', 25)) { if (time() > $start + $to) { if (isset($_SESSION['zipdownload_count'])) { $_SESSION['zipdownload']++; } else { $_SESSION['zipdownload'] = 0; } break; } } } } $filename = $folders ? 'messages' : $imap->get_folder(); if ($mode == 'mbox') { $tempfiles[] = $tmpfname . '.mbox'; fclose($tmpfp); $zip->addFile($tmpfname . '.mbox', $filename . '.mbox'); } $zip->close(); if ($count > 0) { $this->_deliver_zipfile($tmpfname, $filename . ($_SESSION['zipdownload_count'] > 0 ? '(' . $_SESSION['zipdownload_count'] . ')' : '') . '.zip'); // delete temporary files from disk foreach ($tempfiles as $tmpfn) { unlink($tmpfn); } } else { echo html::tag('script', array('type' => 'text/javascript'), 'parent.rcmail.http_post("plugin.zipdownload.abort", "_mbox' . $mbox . '");' . "\r\n" . 'parent.rcmail.set_busy(false, "loading", parent.lock);'); } exit; }
/** * Helper method to packs all the given messages into a zip archive * * @param array List of message UIDs to download */ private function _download_messages($messageset) { $rcmail = rcmail::get_instance(); $imap = $rcmail->get_storage(); $mode = rcube_utils::get_input_value('_mode', rcube_utils::INPUT_POST); $temp_dir = $rcmail->config->get('temp_dir'); $tmpfname = tempnam($temp_dir, 'zipdownload'); $tempfiles = array($tmpfname); $folders = count($messageset) > 1; // @TODO: file size limit // open zip file $zip = new ZipArchive(); $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE); if ($mode == 'mbox') { $tmpfp = fopen($tmpfname . '.mbox', 'w'); } foreach ($messageset as $mbox => $uids) { $imap->set_folder($mbox); $path = $folders ? str_replace($imap->get_hierarchy_delimiter(), '/', $mbox) . '/' : ''; foreach ($uids as $uid) { $headers = $imap->get_message_headers($uid); if ($mode == 'mbox') { $from = rcube_mime::decode_address_list($headers->from, null, true, $headers->charset, true); $from = array_shift($from); // Mbox format header // @FIXME: \r\n or \n // @FIXME: date format $header = sprintf("From %s %s\r\n", $from ? preg_replace('/\\s/', '-', $from) : 'MAILER-DAEMON', $headers->internaldate); fwrite($tmpfp, $header); // Use stream filter to quote "From " in the message body stream_filter_register('mbox_filter', 'zipdownload_mbox_filter'); $filter = stream_filter_append($tmpfp, 'mbox_filter'); $imap->get_raw_body($uid, $tmpfp); stream_filter_remove($filter); fwrite($tmpfp, "\r\n"); } else { // maildir $subject = rcube_mime::decode_mime_string((string) $headers->subject); $subject = $this->_convert_filename($subject); $subject = substr($subject, 0, 16); $disp_name = ($subject ? $subject : 'message_rfc822') . ".eml"; $disp_name = $path . $uid . "_" . $disp_name; $tmpfn = tempnam($temp_dir, 'zipmessage'); $tmpfp = fopen($tmpfn, 'w'); $imap->get_raw_body($uid, $tmpfp); $tempfiles[] = $tmpfn; fclose($tmpfp); $zip->addFile($tmpfn, $disp_name); } } } $filename = $folders ? 'messages' : $imap->get_folder(); if ($mode == 'mbox') { $tempfiles[] = $tmpfname . '.mbox'; fclose($tmpfp); $zip->addFile($tmpfname . '.mbox', $filename . '.mbox'); } $zip->close(); $this->_deliver_zipfile($tmpfname, $filename . '.zip'); // delete temporary files from disk foreach ($tempfiles as $tmpfn) { unlink($tmpfn); } exit; }
/** * Get message headers for popup window */ function mail_headers($args) { $headers = $args['headers']; $ret = array(); if ($headers->subject) { $ret[] = array('Subject', rcube_mime::decode_header($headers->subject)); } // @TODO: List-Id, others? foreach (array('From', 'To') as $h) { $hl = strtolower($h); if ($headers->{$hl}) { $list = rcube_mime::decode_address_list($headers->{$hl}); foreach ($list as $item) { if ($item['mailto']) { $ret[] = array($h, $item['mailto']); } } } } if ($this->rc->action == 'preview') { $this->rc->output->command('parent.set_env', array('sieve_headers' => $ret)); } else { $this->rc->output->set_env('sieve_headers', $ret); } return $args; }
/** * Handler for POST request to import an event attached to a mail message */ public function mail_import_itip() { $itip_sending = $this->rc->config->get('calendar_itip_send_option', $this->defaults['calendar_itip_send_option']); $uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST); $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST); $mime_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_POST); $status = rcube_utils::get_input_value('_status', rcube_utils::INPUT_POST); $delete = intval(rcube_utils::get_input_value('_del', rcube_utils::INPUT_POST)); $noreply = intval(rcube_utils::get_input_value('_noreply', rcube_utils::INPUT_POST)); $noreply = $noreply || $status == 'needs-action' || $itip_sending === 0; $instance = rcube_utils::get_input_value('_instance', rcube_utils::INPUT_POST); $savemode = rcube_utils::get_input_value('_savemode', rcube_utils::INPUT_POST); $error_msg = $this->gettext('errorimportingevent'); $success = false; $delegate = null; if ($status == 'delegated') { $delegates = rcube_mime::decode_address_list(rcube_utils::get_input_value('_to', rcube_utils::INPUT_POST, true), 1, false); $delegate = reset($delegates); if (empty($delegate) || empty($delegate['mailto'])) { $this->rc->output->command('display_message', $this->gettext('libcalendaring.delegateinvalidaddress'), 'error'); return; } } // successfully parsed events? if ($event = $this->lib->mail_get_itip_object($mbox, $uid, $mime_id, 'event')) { // forward iTip request to delegatee if ($delegate) { $rsvpme = intval(rcube_utils::get_input_value('_rsvp', rcube_utils::INPUT_POST)); $itip = $this->load_itip(); if ($itip->delegate_to($event, $delegate, $rsvpme ? true : false)) { $this->rc->output->show_message('calendar.itipsendsuccess', 'confirmation'); } else { $this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error'); } // the delegator is set to non-participant, thus save as non-blocking $event['free_busy'] = 'free'; } // find writeable calendar to store event $cal_id = !empty($_REQUEST['_folder']) ? rcube_utils::get_input_value('_folder', rcube_utils::INPUT_POST) : null; $dontsave = $_REQUEST['_folder'] === '' && $event['_method'] == 'REQUEST'; $calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL); $calendar = $calendars[$cal_id]; // select default calendar except user explicitly selected 'none' if (!$calendar && !$dontsave) { $calendar = $this->get_default_calendar($event['sensitivity']); } $metadata = array('uid' => $event['uid'], '_instance' => $event['_instance'], 'changed' => is_object($event['changed']) ? $event['changed']->format('U') : 0, 'sequence' => intval($event['sequence']), 'fallback' => strtoupper($status), 'method' => $event['_method'], 'task' => 'calendar'); // update my attendee status according to submitted method if (!empty($status)) { $organizer = null; $emails = $this->get_user_emails(); foreach ($event['attendees'] as $i => $attendee) { if ($attendee['role'] == 'ORGANIZER') { $organizer = $attendee; } else { if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { $event['attendees'][$i]['status'] = strtoupper($status); if (!in_array($event['attendees'][$i]['status'], array('NEEDS-ACTION', 'DELEGATED'))) { $event['attendees'][$i]['rsvp'] = false; } // unset RSVP attribute $metadata['attendee'] = $attendee['email']; $metadata['rsvp'] = $attendee['role'] != 'NON-PARTICIPANT'; $reply_sender = $attendee['email']; $event_attendee = $attendee; } } } // add attendee with this user's default identity if not listed if (!$reply_sender) { $sender_identity = $this->rc->user->list_emails(true); $event['attendees'][] = array('name' => $sender_identity['name'], 'email' => $sender_identity['email'], 'role' => 'OPT-PARTICIPANT', 'status' => strtoupper($status)); $metadata['attendee'] = $sender_identity['email']; } } // save to calendar if ($calendar && $calendar['editable']) { // check for existing event with the same UID $existing = $this->driver->get_event($event, calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_PERSONAL); if ($existing) { // forward savemode for correct updates of recurring events $existing['_savemode'] = $savemode ?: $event['_savemode']; // only update attendee status if ($event['_method'] == 'REPLY') { // try to identify the attendee using the email sender address $existing_attendee = -1; $existing_attendee_emails = array(); foreach ($existing['attendees'] as $i => $attendee) { $existing_attendee_emails[] = $attendee['email']; if ($event['_sender'] && ($attendee['email'] == $event['_sender'] || $attendee['email'] == $event['_sender_utf'])) { $existing_attendee = $i; } } $event_attendee = null; $update_attendees = array(); foreach ($event['attendees'] as $attendee) { if ($event['_sender'] && ($attendee['email'] == $event['_sender'] || $attendee['email'] == $event['_sender_utf'])) { $event_attendee = $attendee; $update_attendees[] = $attendee; $metadata['fallback'] = $attendee['status']; $metadata['attendee'] = $attendee['email']; $metadata['rsvp'] = $attendee['rsvp'] || $attendee['role'] != 'NON-PARTICIPANT'; if ($attendee['status'] != 'DELEGATED') { break; } } else { if (!empty($attendee['delegated-from']) && (stripos($attendee['delegated-from'], $event['_sender']) !== false || stripos($attendee['delegated-from'], $event['_sender_utf']) !== false)) { $update_attendees[] = $attendee; if (!in_array($attendee['email'], $existing_attendee_emails)) { $existing['attendees'][] = $attendee; } } } } // if delegatee has declined, set delegator's RSVP=True if ($event_attendee && $event_attendee['status'] == 'DECLINED' && $event_attendee['delegated-from']) { foreach ($existing['attendees'] as $i => $attendee) { if ($attendee['email'] == $event_attendee['delegated-from']) { $existing['attendees'][$i]['rsvp'] = true; break; } } } // found matching attendee entry in both existing and new events if ($existing_attendee >= 0 && $event_attendee) { $existing['attendees'][$existing_attendee] = $event_attendee; $success = $this->driver->update_attendees($existing, $update_attendees); } else { if (($event['sequence'] >= $existing['sequence'] || $event['changed'] >= $existing['changed']) && $event_attendee) { $existing['attendees'][] = $event_attendee; $success = $this->driver->update_attendees($existing, $update_attendees); } else { $error_msg = $this->gettext('newerversionexists'); } } } else { if ($status == 'declined' && $delete) { $deleted = $this->driver->remove_event($existing, true); $success = true; } else { if ($event['sequence'] >= $existing['sequence'] || $event['changed'] >= $existing['changed']) { $event['id'] = $existing['id']; $event['calendar'] = $existing['calendar']; // preserve my participant status for regular updates if (empty($status)) { $emails = $this->get_user_emails(); foreach ($event['attendees'] as $i => $attendee) { if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { foreach ($existing['attendees'] as $j => $_attendee) { if ($attendee['email'] == $_attendee['email']) { $event['attendees'][$i] = $existing['attendees'][$j]; break; } } } } } // set status=CANCELLED on CANCEL messages if ($event['_method'] == 'CANCEL') { $event['status'] = 'CANCELLED'; } // show me as free when declined (#1670) if ($status == 'declined' || $event['status'] == 'CANCELLED' || $event_attendee['role'] == 'NON-PARTICIPANT') { $event['free_busy'] = 'free'; } $success = $this->driver->edit_event($event); } else { if (!empty($status)) { $existing['attendees'] = $event['attendees']; if ($status == 'declined' || $event_attendee['role'] == 'NON-PARTICIPANT') { // show me as free when declined (#1670) $existing['free_busy'] = 'free'; } $success = $this->driver->edit_event($existing); } else { $error_msg = $this->gettext('newerversionexists'); } } } } } else { if (!$existing && ($status != 'declined' || $this->rc->config->get('kolab_invitation_calendars'))) { if ($status == 'declined' || $event['status'] == 'CANCELLED' || $event_attendee['role'] == 'NON-PARTICIPANT') { $event['free_busy'] = 'free'; } // if the RSVP reply only refers to a single instance: // store unmodified master event with current instance as exception if (!empty($instance) && !empty($savemode) && $savemode != 'all') { $master = $this->lib->mail_get_itip_object($mbox, $uid, $mime_id, 'event'); if ($master['recurrence'] && !$master['_instance']) { // compute recurring events until this instance's date if ($recurrence_date = rcube_utils::anytodatetime($instance, $master['start']->getTimezone())) { $recurrence_date->setTime(23, 59, 59); foreach ($this->driver->get_recurring_events($master, $master['start'], $recurrence_date) as $recurring) { if ($recurring['_instance'] == $instance) { // copy attendees block with my partstat to exception $recurring['attendees'] = $event['attendees']; $master['recurrence']['EXCEPTIONS'][] = $recurring; $event = $recurring; // set reference for iTip reply break; } } $master['calendar'] = $event['calendar'] = $calendar['id']; $success = $this->driver->new_event($master); } else { $master = null; } } else { $master = null; } } // save to the selected/default calendar if (!$master) { $event['calendar'] = $calendar['id']; $success = $this->driver->new_event($event); } } else { if ($status == 'declined') { $error_msg = null; } } } } else { if ($status == 'declined' || $dontsave) { $error_msg = null; } else { $error_msg = $this->gettext('nowritecalendarfound'); } } } if ($success) { $message = $event['_method'] == 'REPLY' ? 'attendeupdateesuccess' : ($deleted ? 'successremoval' : ($existing ? 'updatedsuccessfully' : 'importedsuccessfully')); $this->rc->output->command('display_message', $this->gettext(array('name' => $message, 'vars' => array('calendar' => $calendar['name']))), 'confirmation'); } if ($success || $dontsave) { $metadata['calendar'] = $event['calendar']; $metadata['nosave'] = $dontsave; $metadata['rsvp'] = intval($metadata['rsvp']); $metadata['after_action'] = $this->rc->config->get('calendar_itip_after_action', $this->defaults['calendar_itip_after_action']); $this->rc->output->command('plugin.itip_message_processed', $metadata); $error_msg = null; } else { if ($error_msg) { $this->rc->output->command('display_message', $error_msg, 'error'); } } // send iTip reply if ($event['_method'] == 'REQUEST' && $organizer && !$noreply && !in_array(strtolower($organizer['email']), $emails) && !$error_msg) { $event['comment'] = rcube_utils::get_input_value('_comment', rcube_utils::INPUT_POST); $itip = $this->load_itip(); $itip->set_sender_email($reply_sender); if ($itip->send_itip_message($event, 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status)) { $this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $organizer['name'] ? $organizer['name'] : $organizer['email']))), 'confirmation'); } else { $this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error'); } } $this->rc->output->send(); }
/** * Server-side key pair generation handler */ private function key_generate() { // Crypt_GPG does not support key generation for multiple identities // It is also very slow (which is problematic because it may exceed // request time limit) and requires entropy generator // That's why we use only OpenPGP.js method of key generation return; $user = rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST, true); $pass = rcube_utils::get_input_value('_password', rcube_utils::INPUT_POST, true); $size = (int) rcube_utils::get_input_value('_size', rcube_utils::INPUT_POST); if ($size > 4096) { $size = 4096; } $ident = rcube_mime::decode_address_list($user, 1, false); if (empty($ident)) { $this->rc->output->show_message('enigma.keygenerateerror', 'error'); $this->rc->output->send(); } $this->enigma->load_engine(); $result = $this->enigma->engine->generate_key(array('user' => $ident[1]['name'], 'email' => $ident[1]['mailto'], 'password' => $pass, 'size' => $size)); if ($result instanceof enigma_key) { $this->rc->output->command('enigma_key_create_success'); $this->rc->output->show_message('enigma.keygeneratesuccess', 'confirmation'); } else { $this->rc->output->show_message('enigma.keygenerateerror', 'error'); } $this->rc->output->send(); }
/** * Deprecated methods (to be removed) */ public function decode_address_list($input, $max = null, $decode = true, $fallback = null) { return rcube_mime::decode_address_list($input, $max, $decode, $fallback); }
/** * Helper method to packs all the given messages into a zip archive * * @param array List of message UIDs to download */ private function _download_messages($messageset) { $rcmail = rcmail::get_instance(); $imap = $rcmail->get_storage(); $mode = rcube_utils::get_input_value('_mode', rcube_utils::INPUT_POST); $temp_dir = $rcmail->config->get('temp_dir'); $tmpfname = tempnam($temp_dir, 'zipdownload'); $tempfiles = array($tmpfname); $folders = count($messageset) > 1; // @TODO: file size limit // open zip file $zip = new ZipArchive(); $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE); if ($mode == 'mbox') { $tmpfp = fopen($tmpfname . '.mbox', 'w'); } foreach ($messageset as $mbox => $uids) { $imap->set_folder($mbox); $path = $folders ? str_replace($imap->get_hierarchy_delimiter(), '/', $mbox) . '/' : ''; if ($uids === '*') { $index = $imap->index($mbox, null, null, true); $uids = $index->get(); } foreach ($uids as $uid) { $headers = $imap->get_message_headers($uid); if ($mode == 'mbox') { // Sender address $from = rcube_mime::decode_address_list($headers->from, null, true, $headers->charset, true); $from = array_shift($from); $from = preg_replace('/\\s/', '-', $from); // Received (internal) date $date = rcube_utils::anytodatetime($headers->internaldate); if ($date) { $date->setTimezone(new DateTimeZone('UTC')); $date = $date->format(self::MBOX_DATE_FORMAT); } // Mbox format header (RFC4155) $header = sprintf("From %s %s\r\n", $from ?: 'MAILER-DAEMON', $date ?: ''); fwrite($tmpfp, $header); // Use stream filter to quote "From " in the message body stream_filter_register('mbox_filter', 'zipdownload_mbox_filter'); $filter = stream_filter_append($tmpfp, 'mbox_filter'); $imap->get_raw_body($uid, $tmpfp); stream_filter_remove($filter); fwrite($tmpfp, "\r\n"); } else { // maildir $subject = rcube_mime::decode_header($headers->subject, $headers->charset); $subject = $this->_filename_from_subject(mb_substr($subject, 0, 16)); $subject = $this->_convert_filename($subject); $disp_name = $path . $uid . ($subject ? " {$subject}" : '') . '.eml'; $tmpfn = tempnam($temp_dir, 'zipmessage'); $tmpfp = fopen($tmpfn, 'w'); $imap->get_raw_body($uid, $tmpfp); $tempfiles[] = $tmpfn; fclose($tmpfp); $zip->addFile($tmpfn, $disp_name); } } } $filename = $folders ? 'messages' : $imap->get_folder(); if ($mode == 'mbox') { $tempfiles[] = $tmpfname . '.mbox'; fclose($tmpfp); $zip->addFile($tmpfname . '.mbox', $filename . '.mbox'); } $zip->close(); $this->_deliver_zipfile($tmpfname, $filename . '.zip'); // delete temporary files from disk foreach ($tempfiles as $tmpfn) { unlink($tmpfn); } exit; }