From 80ef9895608be35fe9fada69c1f06c436644bf4a Mon Sep 17 00:00:00 2001 From: Baraka24 Date: Sun, 5 Jan 2025 12:32:01 +0200 Subject: [PATCH] feat(other): add Junk button when Junk folder is configured for an IMAP Server --- modules/core/message_list_functions.php | 4 +- modules/imap/handler_modules.php | 121 +++++++++--------- modules/imap/hm-ews.php | 36 ++++++ modules/imap/hm-imap.php | 3 + .../modules/core/message_list_functions.php | 2 +- tests/phpunit/modules/core/output_modules.php | 8 +- 6 files changed, 104 insertions(+), 70 deletions(-) diff --git a/modules/core/message_list_functions.php b/modules/core/message_list_functions.php index de9a641b5..aa339f628 100644 --- a/modules/core/message_list_functions.php +++ b/modules/core/message_list_functions.php @@ -398,6 +398,7 @@ function message_controls($output_mod) { '
  • '.$output_mod->trans('Unflag').'
  • '. '
  • '.$output_mod->trans('Delete').'
  • '. '
  • '.$output_mod->trans('Archive').'
  • '. + '
  • '.$output_mod->trans('Junk').'
  • '. ''. ''. ''.$output_mod->trans('Read').''. @@ -405,7 +406,8 @@ function message_controls($output_mod) { ''.$output_mod->trans('Flag').''. ''.$output_mod->trans('Unflag').''. ''.$output_mod->trans('Delete').''. - ''.$output_mod->trans('Archive').''; + ''.$output_mod->trans('Archive').''. + ''.$output_mod->trans('Junk').''; if ($output_mod->get('msg_controls_extra')) { $res .= $output_mod->get('msg_controls_extra'); diff --git a/modules/imap/handler_modules.php b/modules/imap/handler_modules.php index 8184bdfbf..0d3de6ccc 100644 --- a/modules/imap/handler_modules.php +++ b/modules/imap/handler_modules.php @@ -1108,12 +1108,12 @@ public function process() { */ class Hm_Handler_imap_message_action extends Hm_Handler_Module { /** - * Read, unread, delete, flag, or unflag a set of message uids + * Read, unread, delete, flag, unflag, archive, or mark as junk a set of message uids */ public function process() { list($success, $form) = $this->process_form(array('action_type', 'message_ids')); if ($success) { - if (in_array($form['action_type'], array('delete', 'read', 'unread', 'flag', 'unflag', 'archive'))) { + if (in_array($form['action_type'], array('delete', 'read', 'unread', 'flag', 'unflag', 'archive', 'junk'))) { $ids = process_imap_message_ids($form['message_ids']); $errs = 0; $msgs = 0; @@ -1121,77 +1121,23 @@ public function process() { $status = array(); foreach ($ids as $server => $folders) { $specials = get_special_folders($this, $server); - $trash_folder = false; - $archive_folder = false; $mailbox = Hm_IMAP_List::get_connected_mailbox($server, $this->cache); if ($mailbox && $mailbox->authed()) { $server_details = $this->user_config->get('imap_servers')[$server]; - if ($form['action_type'] == 'delete') { - if (array_key_exists('trash', $specials)) { - if ($specials['trash']) { - $trash_folder = $specials['trash']; - } elseif ($mailbox->is_imap()) { - Hm_Msgs::add(sprintf('ERRNo trash folder configured for %s', $server_details['name'])); - } - } - } - if ($form['action_type'] == 'archive') { - if(array_key_exists('archive', $specials)) { - if($specials['archive']) { - $archive_folder = $specials['archive']; - } elseif ($mailbox->is_imap()) { - Hm_Msgs::add(sprintf('ERRNo archive folder configured for %s', $server_details['name'])); - } - } - } - foreach ($folders as $folder => $uids) { - $status['imap_'.$server.'_'.$folder] = $imap->folder_state; - - if ($mailbox->is_imap() && $form['action_type'] == 'delete' && $trash_folder && $trash_folder != hex2bin($folder)) { - if (! $mailbox->message_action(hex2bin($folder), 'MOVE', $uids, $trash_folder)['status']) { - $errs++; - } - else { - foreach ($uids as $uid) { - $moved[] = sprintf("imap_%s_%s_%s", $server, $uid, $folder); - } - } - } - elseif ($mailbox->is_imap() && $form['action_type'] == 'archive' && $archive_folder && $archive_folder != hex2bin($folder)) { - /* path according to original option setting */ - if ($this->user_config->get('original_folder_setting', false)) { - $archive_folder .= '/' . hex2bin($folder); - $dest_path_exists = count($mailbox->get_folder_status($archive_folder)); - if (!$dest_path_exists) { - $mailbox->create_folder($archive_folder); - } - } - if (! $mailbox->message_action(hex2bin($folder), 'MOVE', $uids, $archive_folder)['status']) { - $errs++; - } - else { - foreach ($uids as $uid) { - $moved[] = sprintf("imap_%s_%s_%s", $server, $uid, $folder); - } - } - } - else { - if (! $mailbox->message_action(hex2bin($folder), mb_strtoupper($form['action_type']), $uids)['status']) { - $errs++; - } - else { - $msgs += count($uids); - if ($form['action_type'] == 'delete') { - $mailbox->message_action(hex2bin($folder), 'EXPUNGE', $uids); - } - } + $status['imap_'.$server.'_'.$folder] = $mailbox->get_folder_state(); + $action_result = $this->perform_action($mailbox, $form['action_type'], $uids, $folder, $specials, $server_details); + if ($action_result['error']) { + $errs++; + } else { + $msgs += count($uids); + $moved = array_merge($moved, $action_result['moved']); } } } } if ($errs > 0) { - Hm_Msgs::add(sprintf('ERRAn error occurred trying to %s some messages!', $form['action_type'], $server)); + Hm_Msgs::add(sprintf('ERRAn error occurred trying to %s some messages!', $form['action_type'])); } $this->out('move_count', $moved); if (count($status) > 0) { @@ -1200,6 +1146,53 @@ public function process() { } } } + + private function perform_action($mailbox, $action_type, $uids, $folder, $specials, $server_details) { + $error = false; + $moved = array(); + $folder_name = hex2bin($folder); + $special_folder = $this->get_special_folder($action_type, $specials, $server_details); + + if ($special_folder && $special_folder != $folder_name) { + if ($this->user_config->get('original_folder_setting', false)) { + $special_folder .= '/' . $folder_name; + if (!count($mailbox->get_folder_status($special_folder))) { + $mailbox->create_folder($special_folder); + } + } + if (!$mailbox->message_action($folder_name, 'MOVE', $uids, $special_folder)['status']) { + $error = true; + } else { + foreach ($uids as $uid) { + $moved[] = sprintf("imap_%s_%s_%s", $server_details['id'], $uid, $folder); + } + } + } else { + if (!$mailbox->message_action($folder_name, mb_strtoupper($action_type), $uids)['status']) { + $error = true; + } else { + if ($action_type == 'delete') { + $mailbox->message_action($folder_name, 'EXPUNGE', $uids); + } + } + } + return ['error' => $error, 'moved' => $moved]; + } + + private function get_special_folder($action_type, $specials, $server_details) { + $folder = false; + if ($action_type == 'delete' && array_key_exists('trash', $specials)) { + $folder = $specials['trash']; + } elseif ($action_type == 'archive' && array_key_exists('archive', $specials)) { + $folder = $specials['archive']; + } elseif ($action_type == 'junk' && array_key_exists('junk', $specials)) { + $folder = $specials['junk']; + } + if (!$folder && $action_type != 'read' && $action_type != 'unread' && $action_type != 'flag' && $action_type != 'unflag') { + Hm_Msgs::add(sprintf('ERRNo %s folder configured for %s', $action_type, $server_details['name'])); + } + return $folder; + } } /** diff --git a/modules/imap/hm-ews.php b/modules/imap/hm-ews.php index 9b34fa702..efbf7c715 100644 --- a/modules/imap/hm-ews.php +++ b/modules/imap/hm-ews.php @@ -570,6 +570,9 @@ public function message_action($action, $itemIds, $folder=false, $keyword=false) $status = false; $responses = []; switch ($action) { + case 'JUNK' : + $status = $this->move_items_to_junk($itemIds); + break; case 'ARCHIVE': $status = $this->archive_items($itemIds); break; @@ -971,6 +974,39 @@ protected function archive_items($itemIds) { return $result; } + protected function move_items_to_junk($itemIds) { + $result = true; + $folders = $this->get_parent_folders_of_items($itemIds); + foreach ($folders as $folder => $itemIds) { + if ($this->is_distinguished_folder($folder)) { + $folder = new Type\DistinguishedFolderIdType($folder); + } else { + $folder = new Type\FolderIdType($folder); + } + + $junkFolder = new Type\DistinguishedFolderIdType(Type\DistinguishedFolderIdType::JUNK); + $request = [ + 'SourceFolderId' => $folder->toArray(true), + 'DestinationFolderId' => $junkFolder->toArray(true), + 'ItemIds' => [ + 'ItemId' => $itemIds = array_map(function($itemId) { + return (new Type\ItemIdType($itemId))->toArray(); + }, $itemIds), + ] + ]; + + $request = Type::buildFromArray($request); + + try { + $result = $result && $this->ews->MoveItem($request); + } catch (\Exception $e) { + Hm_Msgs::add('ERR' . $e->getMessage()); + $result = false; + } + } + return $result; + } + protected function delete_items($itemIds, $hard = false) { $result = true; try { diff --git a/modules/imap/hm-imap.php b/modules/imap/hm-imap.php index 0a304b63f..d1fd0c3ea 100644 --- a/modules/imap/hm-imap.php +++ b/modules/imap/hm-imap.php @@ -1843,6 +1843,9 @@ public function message_action($action, $uids, $mailbox=false, $keyword=false) { case 'ARCHIVE': $command = "UID STORE $uid_string +FLAGS (\Archive)\r\n"; break; + case 'JUNK': + $command = "UID STORE $uid_string +FLAGS (\Junk)\r\n"; + break; case 'FLAG': $command = "UID STORE $uid_string +FLAGS (\Flagged)\r\n"; break; diff --git a/tests/phpunit/modules/core/message_list_functions.php b/tests/phpunit/modules/core/message_list_functions.php index 6c67482c7..6a7f85ca4 100644 --- a/tests/phpunit/modules/core/message_list_functions.php +++ b/tests/phpunit/modules/core/message_list_functions.php @@ -107,7 +107,7 @@ public function test_icon_callback() { */ public function test_message_controls() { $mod = new Hm_Output_Test(array('msg_controls_extra' => 'foo', 'foo' => 'bar', 'bar' => 'foo'), array('bar')); - $this->assertEquals('
    ReadUnreadFlagUnflagDeleteArchivefoo
    ', message_controls($mod)); + $this->assertEquals('
    ReadUnreadFlagUnflagDeleteArchiveJunkfoo
    ', message_controls($mod)); } /** * @preserveGlobalState disabled diff --git a/tests/phpunit/modules/core/output_modules.php b/tests/phpunit/modules/core/output_modules.php index bee9400f0..dcda3c08e 100644 --- a/tests/phpunit/modules/core/output_modules.php +++ b/tests/phpunit/modules/core/output_modules.php @@ -27,7 +27,7 @@ public function test_search_from_folder_list() { public function test_search_content_start() { $test = new Output_Test('search_content_start', 'core'); $res = $test->run(); - $this->assertEquals(array('
    Search'), $res->output_response); + $this->assertEquals(array('
    Search'), $res->output_response); } /** * @preserveGlobalState disabled @@ -1105,14 +1105,14 @@ public function test_home_password_dialogs() { public function test_message_list_heading() { $test = new Output_Test('message_list_heading', 'core'); $res = $test->run(); - $this->assertEquals(array('
    + $this->assertEquals(array('
    Sources
    '), $res->output_response); $test->handler_response = array('custom_list_controls' => 'foo'); $res = $test->run(); - $this->assertEquals(array('
    foo
    + $this->assertEquals(array('
    foo
    foo
    @@ -1126,7 +1126,7 @@ public function test_message_list_heading() {
    Sources
    '), $res->output_response); $test->handler_response = array('list_path' => 'combined_inbox'); $res = $test->run(); - $this->assertEquals(array('
    + $this->assertEquals(array('