From 0c58a6a2e2a539749ddcf49cd590b07d0a57f7d3 Mon Sep 17 00:00:00 2001 From: Amani Nyumu Date: Sat, 15 Jun 2024 22:05:33 +0100 Subject: [PATCH] [ENH] add functionality to send later scheduled sending --- modules/core/functions.php | 48 +++++++++++++++ modules/imap/functions.php | 66 +++----------------- modules/imap/output_modules.php | 2 +- modules/imap/site.css | 4 +- modules/imap/site.js | 86 +++++++++----------------- modules/smtp/functions.php | 20 ++++++ modules/smtp/hm-mime-message.php | 6 +- modules/smtp/modules.php | 101 ++++++++++++++++++++++++++++--- modules/smtp/setup.php | 7 +++ modules/smtp/site.js | 12 +++- 10 files changed, 226 insertions(+), 126 deletions(-) diff --git a/modules/core/functions.php b/modules/core/functions.php index bf24cffa6c..edb4caaf32 100644 --- a/modules/core/functions.php +++ b/modules/core/functions.php @@ -607,3 +607,51 @@ function get_special_folders($mod, $id) { } return array(); } + +/** + * @subpackage core/functions + */ +if (!hm_exists('get_nexter_date')) { +function get_nexter_date($format, $only_label = false) { + if ($format == 'later_in_day') { + $date_string = 'today 18:00'; + $label = 'Later in the day'; + } elseif ($format == 'tomorrow') { + $date_string = '+1 day 08:00'; + $label = 'Tomorrow'; + } elseif ($format == 'next_weekend') { + $date_string = 'next Saturday 08:00'; + $label = 'Next weekend'; + } elseif ($format == 'next_week') { + $date_string = 'next week 08:00'; + $label = 'Next week'; + } elseif ($format == 'next_month') { + $date_string = 'next month 08:00'; + $label = 'Next month'; + } else { + $date_string = $format; + $label = 'Certain date'; + } + $time = strtotime($date_string); + if ($only_label) { + return [$label, date('D, H:i', $time)]; + } + return date('D, d M Y H:i', $time); +}} + +/** + * @subpackage imap/functions + */ +if (!hm_exists('nexter_formats')) { +function nexter_formats() { + $values = array( + 'tomorrow', + 'next_weekend', + 'next_week', + 'next_month' + ); + if (date('H') <= 16) { + array_push($values, 'later_in_day'); + } + return $values; +}} diff --git a/modules/imap/functions.php b/modules/imap/functions.php index 34e6c7962c..3d77ab3705 100644 --- a/modules/imap/functions.php +++ b/modules/imap/functions.php @@ -1338,74 +1338,26 @@ function parse_snooze_header($snooze_header) return $result; }} -/** - * @subpackage imap/functions - */ -if (!hm_exists('get_snooze_date')) { -function get_snooze_date($format, $only_label = false) { - if ($format == 'later_in_day') { - $date_string = 'today 18:00'; - $label = 'Later in the day'; - } elseif ($format == 'tomorrow') { - $date_string = '+1 day 08:00'; - $label = 'Tomorrow'; - } elseif ($format == 'next_weekend') { - $date_string = 'next Saturday 08:00'; - $label = 'Next weekend'; - } elseif ($format == 'next_week') { - $date_string = 'next week 08:00'; - $label = 'Next week'; - } elseif ($format == 'next_month') { - $date_string = 'next month 08:00'; - $label = 'Next month'; - } else { - $date_string = $format; - $label = 'Certain date'; - } - $time = strtotime($date_string); - if ($only_label) { - return [$label, date('D, H:i', $time)]; - } - return date('D, d M Y H:i', $time); -}} - -/** - * @subpackage imap/functions - */ -if (!hm_exists('snooze_formats')) { -function snooze_formats() { - $values = array( - 'tomorrow', - 'next_weekend', - 'next_week', - 'next_month' - ); - if (date('H') <= 16) { - array_push($values, 'later_in_day'); - } - return $values; -}} - /** * @subpackage imap/functions */ if (!hm_exists('snooze_dropdown')) { function snooze_dropdown($output, $unsnooze = false) { - $values = snooze_formats(); + $values = nexter_formats(); $txt = ''; diff --git a/modules/imap/output_modules.php b/modules/imap/output_modules.php index 8de62710ee..d74f872d18 100644 --- a/modules/imap/output_modules.php +++ b/modules/imap/output_modules.php @@ -190,7 +190,7 @@ protected function output() { elseif ($fld == 'x-snoozed') { $snooze_header = parse_snooze_header($value); $txt .= ''; - $txt .= $this->trans('Snoozed').''.$this->trans('Until').' '.$this->html_safe($snooze_header['until']).' Unsnooze'; + $txt .= $this->trans('Snoozed').''.$this->trans('Until').' '.$this->html_safe($snooze_header['until']).' Unsnooze'; } elseif ($fld == 'date') { try { diff --git a/modules/imap/site.css b/modules/imap/site.css index 36696f622d..8ee141e14e 100644 --- a/modules/imap/site.css +++ b/modules/imap/site.css @@ -126,7 +126,7 @@ .header_links { padding-top: 10px !important; } -.header_links #dropdownMenuSnooze { +.header_links #dropdownMenuNexterDate { padding: 0; border: unset; font-variant: inherit; @@ -134,7 +134,7 @@ font-size: inherit; vertical-align: baseline; } -.header_links #dropdownMenuSnooze:hover { +.header_links #dropdownMenuNexterDate:hover { background-color: inherit; color: inherit; } diff --git a/modules/imap/site.js b/modules/imap/site.js index 711c36b530..2b8833d2b3 100644 --- a/modules/imap/site.js +++ b/modules/imap/site.js @@ -1072,61 +1072,6 @@ var imap_folder_status = function() { } }; -var imap_setup_snooze = function() { - $(document).on('click', '.snooze_date_picker', function(e) { - document.querySelector('.snooze_input_date').showPicker(); - }); - $(document).on('click', '.snooze_helper', function(e) { - e.preventDefault(); - $('.snooze_input').val($(this).attr('data-value')).trigger('change'); - }); - $(document).on('input', '.snooze_input_date', function(e) { - var now = new Date(); - now.setMinutes(now.getMinutes() + 1); - $(this).attr('min', now.toJSON().slice(0, 16)); - if (new Date($(this).val()).getTime() <= now.getTime()) { - $('.snooze_date_picker').css('border', '1px solid red'); - } else { - $('.snooze_date_picker').css({'border': 'unset', 'border-top': '1px solid #ddd'}); - } - }); - $(document).on('change', '.snooze_input_date', function(e) { - if ($(this).val() && new Date().getTime() < new Date($(this).val()).getTime()) { - $('.snooze_input').val($(this).val()).trigger('change'); - } - }); - $(document).on('change', '.snooze_input', function(e) { - $('.snooze_dropdown').hide(); - var ids = []; - if (hm_page_name() == 'message') { - var list_path = hm_list_path().split('_'); - ids.push(list_path[1]+'_'+hm_msg_uid()+'_'+list_path[2]); - } else { - $('input[type=checkbox]').each(function() { - if (this.checked && this.id.search('imap') != -1) { - var parts = this.id.split('_'); - ids.push(parts[1]+'_'+parts[2]+'_'+parts[3]); - } - }); - if (ids.length == 0) { - return; - }; - } - Hm_Ajax.request( - [{'name': 'hm_ajax_hook', 'value': 'ajax_imap_snooze'}, - {'name': 'imap_snooze_ids', 'value': ids}, - {'name': 'imap_snooze_until', 'value': $(this).val()}], - function(res) { - if (res.snoozed_messages > 0) { - Hm_Folders.reload_folders(true); - var path = hm_list_parent()? hm_list_parent(): hm_list_path(); - window.location.replace('?page=message_list&list_path='+path); - } - } - ); - }); -} - var imap_unsnooze_messages = function() { Hm_Ajax.request( [{'name': 'hm_ajax_hook', 'value': 'ajax_imap_unsnooze'}], @@ -1184,7 +1129,36 @@ $(function() { } if (hm_page_name() === 'message_list' || hm_page_name() === 'message') { - imap_setup_snooze(); + setup_nexter_date(function(e) { + $('.snooze_dropdown').hide(); + var ids = []; + if (hm_page_name() == 'message') { + var list_path = hm_list_path().split('_'); + ids.push(list_path[1]+'_'+hm_msg_uid()+'_'+list_path[2]); + } else { + $('input[type=checkbox]').each(function() { + if (this.checked && this.id.search('imap') != -1) { + var parts = this.id.split('_'); + ids.push(parts[1]+'_'+parts[2]+'_'+parts[3]); + } + }); + if (ids.length == 0) { + return; + }; + } + Hm_Ajax.request( + [{'name': 'hm_ajax_hook', 'value': 'ajax_imap_snooze'}, + {'name': 'imap_snooze_ids', 'value': ids}, + {'name': 'imap_snooze_until', 'value': $(this).val()}], + function(res) { + if (res.snoozed_messages > 0) { + Hm_Folders.reload_folders(true); + var path = hm_list_parent()? hm_list_parent(): hm_list_path(); + window.location.replace('?page=message_list&list_path='+path); + } + } + ); + }); } if (hm_is_logged()) { diff --git a/modules/smtp/functions.php b/modules/smtp/functions.php index 260ad84e87..560899cbb1 100644 --- a/modules/smtp/functions.php +++ b/modules/smtp/functions.php @@ -42,6 +42,26 @@ function connect_to_smtp_server($address, $name, $port, $user, $pass, $tls, $ser } } +if (!hm_exists('schedule_dropdown')) { +function schedule_dropdown($output) { + $values = nexter_formats(); + + $txt = '
+
'; + + return $txt; +}} + + if (!hm_exists('delete_smtp_server')) { function delete_smtp_server($smtp_server_id) { Hm_SMTP_List::del($smtp_server_id); diff --git a/modules/smtp/hm-mime-message.php b/modules/smtp/hm-mime-message.php index 45f7d87002..f16af42ac2 100644 --- a/modules/smtp/hm-mime-message.php +++ b/modules/smtp/hm-mime-message.php @@ -21,10 +21,14 @@ class Hm_MIME_Msg { private $final_msg = ''; /* build mime message data */ - function __construct($to, $subject, $body, $from, $html=false, $cc='', $bcc='', $in_reply_to_id='', $from_name='', $reply_to='') { + function __construct($to, $subject, $body, $from, $html=false, $cc='', $bcc='', $in_reply_to_id='', $from_name='', $reply_to='', $schedule='') { if ($cc) { $this->headers['Cc'] = $cc; } + if ($schedule) { + $this->headers['X-Schedule'] = $schedule; + } + if ($in_reply_to_id) { $this->headers['In-Reply-To'] = $in_reply_to_id; } diff --git a/modules/smtp/modules.php b/modules/smtp/modules.php index 0028b5e182..a8d8f5f44a 100644 --- a/modules/smtp/modules.php +++ b/modules/smtp/modules.php @@ -114,6 +114,8 @@ public function process() { } } + + /** * @subpackage smtp/handler */ @@ -164,6 +166,7 @@ public function process() { } } + /** * @subpackage smtp/handler */ @@ -273,6 +276,7 @@ public function process() { $draft_id = array_key_exists('draft_id', $this->request->post) ? $this->request->post['draft_id'] : false; $draft_notice = array_key_exists('draft_notice', $this->request->post) ? $this->request->post['draft_notice'] : false; $uploaded_files = array_key_exists('uploaded_files', $this->request->post) ? $this->request->post['uploaded_files'] : false; + $schedule=array_key_exists('schedule', $this->request->post) ? $this->request->post['schedule'] : ''; if (array_key_exists('delete_uploaded_files', $this->request->post) && $this->request->post['delete_uploaded_files']) { delete_uploaded_files($this->session, $draft_id); @@ -287,11 +291,12 @@ public function process() { } $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, + 'draft_in_reply_to' => $inreplyto, 'schedule'=>$schedule), $draft_id, $this->session, $this, $this->cache, $uploaded_files); if ($new_draft_id >= 0) { if ($draft_notice) { - Hm_Msgs::add('Draft saved'); + $msg = $schedule ? 'Message scheduled to be sent later' : 'Draft saved'; + Hm_Msgs::add($msg); } $this->out('draft_id', $new_draft_id); } @@ -629,6 +634,30 @@ function get_mime_type($filename) } } +class Hm_Handler_process_schedule_sending extends Hm_Handler_Module +{ + public function process() + { + // Check if the user has selected to send the email tomorrow morning at 08:00 AM + if(array_key_exists('send_tomorrow_morning', $this->request->post)) { + die("send_tomorrow_morning"); + } + // Check if the user has selected to send the email send_today_afternoon at 1:00 PM + if(array_key_exists('send_today_afternoon', $this->request->post)) { + die("send_today_afternoon"); + } + // Check if the user has selected to send the email schedule_sending + if(array_key_exists('schedule_sending', $this->request->post)) { + list($success, $form) = $this->process_form(array('send_date', 'send_time')); + if($success){ + var_dump($this->request->post['send_date'] , $this->request->post['send_time']); + die(); + } + } + } + +} + /** * @subpackage smtp/handler */ @@ -1186,11 +1215,57 @@ protected function output() { } } } - + $date = new DateTimeImmutable(); + $Tomorrow_morning = "Send Tomorrow Morning {$date->modify('+1 day')->format('d F')} at 08:00 AM"; + $afternoon=$date->setTime(13,00)->format('H:i:s'); + if($date->format('H:i:s')>$afternoon){ + $Send_afternoon="Send Tomorrow Afternoon {$date->modify('+1 day')->format('d F')} at 1:00 PM"; + }else{ + $Send_afternoon="Send Today Afternoon {$date->format('d F')} at 1:00 PM"; + } + $res .= ''. smtp_server_dropdown($this->module_output(), $this, $recip, $selected_id). - ''; + '
+ + + '.schedule_dropdown($this).' +
'. + ' + + + + '; if ($this->get('list_path') && ($reply_type == 'reply' || $reply_type == 'reply_all')) { $res .= ''; } @@ -1847,13 +1922,22 @@ function save_imap_draft($atts, $id, $session, $mod, $mod_cache, $uploaded_files $specials = get_special_folders($mod, $imap_profile['id']); - if (!array_key_exists('draft', $specials) || !$specials['draft']) { + if ((!array_key_exists('draft', $specials) || !$specials['draft']) && !array_key_exists('schedule', $atts)) { Hm_Msgs::add('ERRThere is no draft directory configured for this account.'); return -1; } $cache = Hm_IMAP_List::get_cache($mod_cache, $imap_profile['id']); $imap = Hm_IMAP_List::connect($imap_profile['id'], $cache); - $draft_folder = $imap->select_mailbox($specials['draft']); + + if (!empty($atts['schedule'])) { + $folder ='Scheduled'; + if (!count($imap->get_mailbox_status($folder))) { + $imap->create_mailbox($folder); + } + } else { + $folder = $specials['draft']; + } + $imap->select_mailbox($folder); $mime = new Hm_MIME_Msg( $atts['draft_to'], @@ -1865,7 +1949,8 @@ function save_imap_draft($atts, $id, $session, $mod, $mod_cache, $uploaded_files $atts['draft_bcc'], '', $name, - $atts['draft_in_reply_to'] + $atts['draft_in_reply_to'], + $atts['schedule'] ); $mime->add_attachments($uploaded_files); @@ -1875,7 +1960,7 @@ function save_imap_draft($atts, $id, $session, $mod, $mod_cache, $uploaded_files $msg = str_replace("\n", "\r\n", $msg); $msg = rtrim($msg)."\r\n"; - if ($imap->append_start($specials['draft'], strlen($msg), false, true)) { + if ($imap->append_start($folder, strlen($msg), false, true)) { $imap->append_feed($msg."\r\n"); if (!$imap->append_end()) { Hm_Msgs::add('ERRAn error occurred saving the draft message'); diff --git a/modules/smtp/setup.php b/modules/smtp/setup.php index 684ad9afc5..3925ae3afe 100644 --- a/modules/smtp/setup.php +++ b/modules/smtp/setup.php @@ -12,6 +12,7 @@ add_handler('compose', 'load_smtp_servers_from_config', true, 'smtp', 'load_smtp_reply_to_details', 'after'); add_handler('compose', 'add_smtp_servers_to_page_data', true, 'smtp', 'load_smtp_servers_from_config', 'after'); add_handler('compose', 'process_compose_form_submit', true, 'smtp', 'load_smtp_servers_from_config', 'after'); +add_handler('compose', 'process_schedule_sending', true, 'smtp', 'load_smtp_servers_from_config', 'after'); add_output('compose', 'compose_form_start', true, 'smtp', 'content_section_start', 'after'); add_output('compose', 'compose_form_draft_list', true, 'smtp', 'compose_form_start', 'before'); add_output('compose', 'compose_form_content', true, 'smtp', 'compose_form_start', 'after'); @@ -19,6 +20,7 @@ add_output('compose', 'compose_form_attach', true, 'smtp', 'compose_form_end', 'after'); add_handler('compose', 'load_smtp_is_imap_forward', true, 'smtp', 'load_user_data', 'after'); + add_handler('functional_api', 'default_smtp_server', true, 'smtp'); add_handler('profiles', 'load_smtp_servers_from_config', true, 'smtp', 'load_user_data', 'after'); @@ -142,6 +144,11 @@ ), 'allowed_post' => array( 'post_archive' => FILTER_VALIDATE_INT, + 'send_tomorrow_morning' => FILTER_DEFAULT, + 'send_today_afternoon' => FILTER_DEFAULT, + 'schedule_sending' => FILTER_DEFAULT, + 'send_date' => FILTER_DEFAULT, + 'send_time' => FILTER_DEFAULT, 'attachment_id' => FILTER_DEFAULT, 'smtp_compose_type' => FILTER_VALIDATE_INT, 'new_smtp_name' => FILTER_DEFAULT, diff --git a/modules/smtp/site.js b/modules/smtp/site.js index e08c0df92b..65bcb3e5c9 100644 --- a/modules/smtp/site.js +++ b/modules/smtp/site.js @@ -113,7 +113,7 @@ var send_archive = function() { document.getElementsByClassName("smtp_send_placeholder")[0].click(); } -var save_compose_state = function(no_files, notice) { +var save_compose_state = function(no_files, notice, schedule, callback = false) { var no_icon = true; if (notice) { no_icon = false; @@ -151,6 +151,7 @@ var save_compose_state = function(no_files, notice) { {'name': 'draft_in_reply_to', 'value': inreplyto}, {'name': 'delete_uploaded_files', 'value': no_files}, {'name': 'draft_to', 'value': to}, + {'name': 'schedule', 'value': schedule}, {'name': 'uploaded_files', 'value': uploaded_files}], function(res) { $('.smtp_send_placeholder').prop('disabled', false); @@ -161,6 +162,9 @@ var save_compose_state = function(no_files, notice) { if (res.draft_subject) { $('.draft_list .draft_'+draft_id+' a').text(res.draft_subject); } + if (callback) { + callback(); + } }, [], no_icon @@ -437,6 +441,12 @@ $(function () { } if (hm_page_name() === 'compose') { init_resumable_upload() + setup_nexter_date(function() { + save_compose_state(false, true, $(this).val(), function() { + reset_smtp_form(); + Hm_Utils.redirect(); + }); + }); var interval = Hm_Utils.get_from_global('compose_save_interval', 30); Hm_Timer.add_job(function() { save_compose_state(); }, interval, true);