diff --git a/modules/core/message_list_functions.php b/modules/core/message_list_functions.php index 47ffd723a4..efbba7e2f5 100644 --- a/modules/core/message_list_functions.php +++ b/modules/core/message_list_functions.php @@ -296,6 +296,10 @@ function icon_callback($vals, $style, $output_mod) { $icons .= $show_icons ? '' : ' F'; $title[] = $output_mod->trans('Flagged'); } + if (in_array('draft', $vals[0])) { + $icons .= $show_icons ? '' : ' D'; + $title[] = $output_mod->trans('Draft'); + } if (in_array('answered', $vals[0])) { $icons .= $show_icons ? '' : ' A'; $title[] = $output_mod->trans('Answered'); diff --git a/modules/imap/functions.php b/modules/imap/functions.php index f3033a2dc0..9af6cd734b 100644 --- a/modules/imap/functions.php +++ b/modules/imap/functions.php @@ -221,7 +221,7 @@ function format_imap_message_list($msg_list, $output_module, $parent_list=false, $from = preg_replace("/(\<.+\>)/U", '', $msg['to']); $icon = 'sent'; } - foreach (array('attachment', 'deleted', 'flagged', 'answered') as $flag) { + foreach (array('attachment', 'deleted', 'flagged', 'answered', 'draft') as $flag) { if (stristr($msg['flags'], $flag)) { $flags[] = $flag; } @@ -244,6 +244,11 @@ function format_imap_message_list($msg_list, $output_module, $parent_list=false, if (!$show_icons) { $icon = false; } + + if (in_array('draft', $flags)) { + $url = '?page=compose&list_path='.sprintf('imap_%s_%s', $msg['server_id'], $msg['folder']).'&uid='.$msg['uid'].'&imap_draft=1'; + } + if ($style == 'news') { $res[$id] = message_list_row(array( array('checkbox_callback', $id), diff --git a/modules/imap/hm-imap.php b/modules/imap/hm-imap.php index 45efffba87..dc8e65fd9c 100644 --- a/modules/imap/hm-imap.php +++ b/modules/imap/hm-imap.php @@ -897,7 +897,6 @@ private function parse_bodystructure_response($result) { * get content for a message part * @param int $uid a single IMAP message UID * @param string $message_part the IMAP message part number - * @param bool $raw flag to enabled fetching the entire message as text * @param int $max maximum read length to allow. * @param mixed $struct a message part structure array for decoding and * charset conversion. bool true for auto discovery @@ -1595,7 +1594,7 @@ public function message_action($action, $uids, $mailbox=false, $keyword=false) { * @param bool $seen flag to mark the message seen * $return bool true on success */ - public function append_start($mailbox, $size, $seen=true) { + public function append_start($mailbox, $size, $seen=true, $draft=false) { if (!$this->is_clean($mailbox, 'mailbox') || !$this->is_clean($size, 'uid')) { return false; } @@ -1605,6 +1604,9 @@ public function append_start($mailbox, $size, $seen=true) { else { $command = 'APPEND "'.$this->utf7_encode($mailbox).'" () {'.$size."}\r\n"; } + if ($draft) { + $command = 'APPEND "'.$this->utf7_encode($mailbox).'" (\Draft) {'.$size."}\r\n"; + } $this->send_command($command); $result = $this->fgets(); if (substr($result, 0, 1) == '+') { diff --git a/modules/imap_folders/setup.php b/modules/imap_folders/setup.php index a91f75ab32..3fb8e4f490 100644 --- a/modules/imap_folders/setup.php +++ b/modules/imap_folders/setup.php @@ -26,7 +26,7 @@ add_output('folders', 'folders_trash_dialog', true, 'imap_folders', 'folders_delete_dialog', 'after'); add_output('folders', 'folders_sent_dialog', true, 'imap_folders', 'folders_trash_dialog', 'after'); add_output('folders', 'folders_archive_dialog', true, 'imap_folders', 'folders_sent_dialog', 'after'); -//add_output('folders', 'folders_draft_dialog', true, 'imap_folders', 'folders_sent_dialog', 'after'); +add_output('folders', 'folders_draft_dialog', true, 'imap_folders', 'folders_sent_dialog', 'after'); add_handler('compose', 'special_folders', true, 'imap_folders', 'load_user_data', 'after'); diff --git a/modules/smtp/hm-mime-message.php b/modules/smtp/hm-mime-message.php index 6206c135f1..0c2c8dca8a 100644 --- a/modules/smtp/hm-mime-message.php +++ b/modules/smtp/hm-mime-message.php @@ -50,6 +50,11 @@ function __construct($to, $subject, $body, $from, $html=false, $cc='', $bcc='', $this->body = $body; } + /* return headers array */ + function get_headers() { + return $this->headers; + } + /* add attachments */ function add_attachments($files) { $this->attachments = $files; @@ -267,4 +272,3 @@ function qp_encode($string) { return str_replace('.', '=2E', quoted_printable_encode($string)); } } - diff --git a/modules/smtp/modules.php b/modules/smtp/modules.php index 9c1bf4a547..a21b41c3a4 100644 --- a/modules/smtp/modules.php +++ b/modules/smtp/modules.php @@ -31,6 +31,50 @@ public function process() { } } +/** + * @subpackage smtp/handler + */ +class Hm_Handler_load_smtp_is_imap_draft extends Hm_Handler_Module { + public function process() { + if (!$this->module_is_supported('imap')) { + Hm_Msgs::add('ERRIMAP module unavailable.'); + return; + } + if (array_key_exists('imap_draft', $this->request->get) + && array_key_exists('list_path', $this->request->get) + && array_key_exists('uid', $this->request->get)) { + $path = explode('_', $this->request->get['list_path']); + + $imap = Hm_IMAP_List::connect($path[1]); + if ($imap->select_mailbox(hex2bin($path[2]))) { + $msg_struct = $imap->get_message_structure($this->request->get['uid']); + list($part, $msg_text) = $imap->get_first_message_part($this->request->get['uid'], 'text', 'plain', $msg_struct); + $msg_header = $imap->get_message_headers($this->request->get['uid']); + + $imap_draft = array( + 'From' => $msg_header['From'], + 'To' => $msg_header['To'], + 'Subject' => $msg_header['Subject'], + 'Message-Id' => $msg_header['Message-Id'], + 'Content-Type' => $msg_header['Content-Type'], + 'Body' => $msg_text + ); + + if (array_key_exists('Cc', $msg_header)) { + $imap_draft['Cc'] = $msg_header['Cc']; + } + + if ($imap_draft) { + $this->out('draft_id', $this->request->get['uid']); + $this->out('imap_draft', $imap_draft); + } + return; + } + Hm_Msgs::add('ERRCould not load the IMAP mailbox.'); + } + } +} + /** * @subpackage smtp/handler */ @@ -106,7 +150,7 @@ public function process() { if (!is_readable($file['tmp_name'])) { if($file['error'] == 1) { $upload_max_filesize = ini_get('upload_max_filesize'); - Hm_Msgs::add('ERRYour upload failed because you reached the limit of ' . $upload_max_filesize . '.'); + Hm_Msgs::add('ERRYour upload failed because you reached the limit of ' . $upload_max_filesize . '.'); return; } Hm_Msgs::add('ERRAn error occurred saving the uploaded file.'); @@ -166,6 +210,20 @@ public function process() { delete_draft($draft_id, $this->session); } else { + if ($this->module_is_supported('imap')) { + $new_draft_id = save_imap_draft(array('draft_smtp' => $smtp, 'draft_to' => $to, 'draft_body' => $body, + 'draft_subject' => $subject, 'draft_cc' => $cc, 'draft_bcc' => $bcc, + 'draft_in_reply_to' => $inreplyto), $draft_id, $this->session, + $this, $this->cache); + if ($new_draft_id) { + Hm_Msgs::add('Draft saved'); + $this->out('draft_id', $new_draft_id); + } elseif ($draft_notice) { + Hm_Msgs::add('ERRYou must enter a subject to save a draft'); + } + return; + } + if (save_draft(array('draft_smtp' => $smtp, 'draft_to' => $to, 'draft_body' => $body, 'draft_subject' => $subject, 'draft_cc' => $cc, 'draft_bcc' => $bcc, 'draft_in_reply_to' => $inreplyto), $draft_id, $this->session) !== false) { @@ -619,6 +677,7 @@ protected function output() { $draft = $this->get('compose_draft', array()); $reply = $this->get('reply_details', array()); + $imap_draft = $this->get('imap_draft', array()); $reply_type = $this->get('reply_type', ''); $html = $this->get('smtp_compose_type', 0); $msg_path = $this->get('list_path', ''); @@ -633,6 +692,7 @@ protected function output() { } $smtp_id = false; $draft_id = $this->get('compose_draft_id', 0); + if (!empty($reply)) { list($to, $cc, $subject, $body, $in_reply_to) = format_reply_fields( $reply['msg_text'], $reply['msg_headers'], $reply['msg_struct'], $html, $this, $reply_type); @@ -640,7 +700,8 @@ protected function output() { $recip = get_primary_recipient($this->get('compose_profiles', array()), $reply['msg_headers'], $this->get('smtp_servers', array())); } - elseif (!empty($draft)) { + + if (!empty($draft)) { if (array_key_exists('draft_to', $draft)) { $to = $draft['draft_to']; } @@ -663,6 +724,23 @@ protected function output() { $bcc = $draft['draft_bcc']; } } + + if ($imap_draft) { + if (array_key_exists('Body', $imap_draft)) { + $body= $imap_draft['Body']; + } + if (array_key_exists('To', $imap_draft)) { + $to= $imap_draft['To']; + } + if (array_key_exists('Subject', $imap_draft)) { + $subject= $imap_draft['Subject']; + } + if (array_key_exists('Cc', $imap_draft)) { + $cc= $imap_draft['Cc']; + } + $draft_id = $msg_uid; + } + $send_disabled = ''; if (count($this->get('smtp_servers', array())) == 0) { $send_disabled = 'disabled="disabled" '; @@ -708,10 +786,28 @@ protected function output() { $res .= format_attachment_row($file, $this); } - // If compose_from GET parameter is set, force $recip replacement. - // This ensures any module can force the selected dropdown SMTP server + // If compose_from GET parameter is set, search for the correct smtp_id + // within the SMTP profiles. + // + // Added latency reduction 'break' for big smtp profile lists if ($from) { - $recip = $from; + $profiles = $this->module_output()['smtp_servers']; + foreach ($profiles as $id => $profile) { + if ($profile['user'] == $from) { + $smtp_id = $id; + } + // Profile users without the domain + if ($profile['user'] == explode('@', $from)[0]) { + $smtp_id = $id; + } + // Some users might use the profile name as the full email + if ($profile['name'] == $from) { + $smtp_id = $id; + } + if ($smtp_id) { + break; + } + } } $res .= ''. @@ -856,7 +952,7 @@ protected function output() { $res .= '