diff --git a/language/az.php b/language/az.php
index 5e1c54a187..e3f91e1ced 100755
--- a/language/az.php
+++ b/language/az.php
@@ -621,6 +621,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/de.php b/language/de.php
index 7150e9c182..8bd66b1a43 100755
--- a/language/de.php
+++ b/language/de.php
@@ -618,6 +618,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/en.php b/language/en.php
index f630f6a2d3..5cd8c300ef 100755
--- a/language/en.php
+++ b/language/en.php
@@ -636,6 +636,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/es.php b/language/es.php
index fa551b1ea9..c253b1f363 100755
--- a/language/es.php
+++ b/language/es.php
@@ -618,6 +618,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/et.php b/language/et.php
index 61b7b6addb..53e6207a9f 100755
--- a/language/et.php
+++ b/language/et.php
@@ -626,6 +626,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/fa.php b/language/fa.php
index b2ad0e2221..9431100de7 100755
--- a/language/fa.php
+++ b/language/fa.php
@@ -670,6 +670,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/fr.php b/language/fr.php
index b60c7c3592..8e0550fc0e 100755
--- a/language/fr.php
+++ b/language/fr.php
@@ -617,6 +617,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => 'Vous avez %d messages programmés qui ne seront pas exécutés si vous quittez',
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/hu.php b/language/hu.php
index e91cd6a66d..7e9b587059 100755
--- a/language/hu.php
+++ b/language/hu.php
@@ -618,6 +618,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/id.php b/language/id.php
index 07b205ab8b..95c4ac6a5f 100755
--- a/language/id.php
+++ b/language/id.php
@@ -625,6 +625,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/it.php b/language/it.php
index 5147b4e8ad..d720e4214a 100755
--- a/language/it.php
+++ b/language/it.php
@@ -618,6 +618,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/ja.php b/language/ja.php
index 30596c066d..7c7d601ac5 100755
--- a/language/ja.php
+++ b/language/ja.php
@@ -618,6 +618,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/nl.php b/language/nl.php
index 1d1db295cc..82e94158d6 100755
--- a/language/nl.php
+++ b/language/nl.php
@@ -618,6 +618,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/pt-BR.php b/language/pt-BR.php
index 1fcf9142ec..7ad23625b8 100755
--- a/language/pt-BR.php
+++ b/language/pt-BR.php
@@ -617,6 +617,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/ro.php b/language/ro.php
index 5a52506d25..c019b88263 100755
--- a/language/ro.php
+++ b/language/ro.php
@@ -617,6 +617,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/ru.php b/language/ru.php
index 60813edac2..70cd16aa1c 100755
--- a/language/ru.php
+++ b/language/ru.php
@@ -619,6 +619,7 @@
'You must provide a name for your script' => false,
'Empty script' => false,
'Please create a profile for saving sent messages option' => false,
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => false,
'Your subject is empty!' => false,
'Your body is empty!' => false,
diff --git a/language/zh-Hans.php b/language/zh-Hans.php
index 8baf2310ff..526e932c4a 100644
--- a/language/zh-Hans.php
+++ b/language/zh-Hans.php
@@ -639,6 +639,7 @@
'You must provide a name for your script' => '请提供脚本名称',
'Empty script' => '空脚本',
'Please create a profile for saving sent messages option' => '请创建用于保存已发送信息选项的配置文件',
+ 'You have %d scheduled messages that won\'t be executed if you quit' => false,
'Attachment storage unavailable, please contact your site administrator' => '附件存储不可用,请联系您的网站管理员',
'Your subject is empty!' => '主题为空!',
'Your body is empty!' => '内容为空!',
diff --git a/modules/core/functions.php b/modules/core/functions.php
index 1e224fff70..a422a0858b 100644
--- a/modules/core/functions.php
+++ b/modules/core/functions.php
@@ -637,3 +637,99 @@ function privacy_setting_callback($val, $key, $mod) {
}
return $val;
}
+
+if (!hm_exists('get_scheduled_date')) {
+function get_scheduled_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;
+}}
+
+if (!hm_exists('schedule_dropdown')) {
+function schedule_dropdown($output, $send_now = false) {
+ $values = nexter_formats();
+
+ $txt = '';
+ if ($send_now) {
+ $txt .= '
+ ';
+ }
+ $txt .= '';
+ if ($send_now) {
+ $txt .= '
';
+ }
+
+ return $txt;
+}}
+
+/**
+ * @subpackage imap/functions
+ */
+if (!hm_exists('parse_nexter_header')) {
+ function parse_nexter_header($header, $name)
+ {
+ $header = str_replace("$name: ", '', $header);
+ $result = [];
+ foreach (explode(';', $header) as $kv)
+ {
+ $kv = trim($kv);
+ $spacePos = strpos($kv, ' ');
+ if ($spacePos > 0) {
+ $result[rtrim(substr($kv, 0, $spacePos), ':')] = trim(substr($kv, $spacePos+1));
+ } else {
+ $result[$kv] = true;
+ }
+ }
+ return $result;
+ }}
diff --git a/modules/core/message_list_functions.php b/modules/core/message_list_functions.php
index 02c2d61dea..36bf2788fa 100644
--- a/modules/core/message_list_functions.php
+++ b/modules/core/message_list_functions.php
@@ -322,11 +322,11 @@ function subject_callback($vals, $style, $output_mod) {
*/
if (!hm_exists('date_callback')) {
function date_callback($vals, $style, $output_mod) {
- $snooze_class = isset($vals[2]) && $vals[2]? ' snoozed_date': '';
+ $nexter_class = isset($vals[2]) && $vals[2]? ' nexter_date': '';
if ($style == 'news') {
- return sprintf('
Loading...
@@ -1716,7 +1719,7 @@ var hm_spinner = function(type = 'border', size = '') {
`
};
-var fillImapData = function(details) {
+var fillImapData = function (details) {
$('#srv_setup_stepper_imap_address').val(details.server);
$('#srv_setup_stepper_imap_port').val(details.port);
$('#srv_setup_stepper_imap_server_id').val(details.id);
@@ -1725,31 +1728,31 @@ var fillImapData = function(details) {
$('#srv_setup_stepper_imap_sieve_host').val(details.sieve_config_host);
$("#srv_setup_stepper_enable_sieve").trigger("click", false);
$('#srv_setup_stepper_imap_sieve_mode_tls')
- .prop('checked', details.tls)
- .trigger('change');
+ .prop('checked', details.tls)
+ .trigger('change');
}
- if(details.tls) {
+ if (details.tls) {
$("input[name='srv_setup_stepper_imap_tls'][value='true']").prop("checked", true);
} else {
$("input[name='srv_setup_stepper_imap_tls'][value='false']").prop("checked", true);
}
};
-var fillSmtpData = function(details) {
+var fillSmtpData = function (details) {
$('#srv_setup_stepper_smtp_server_id').val(details.id);
$('#srv_setup_stepper_smtp_address').val(details.server);
$('#srv_setup_stepper_smtp_port').val(details.port);
};
-var fillJmapData = function(details) {
+var fillJmapData = function (details) {
$('#srv_setup_stepper_imap_server_id').val(details.id);
$('#srv_setup_stepper_only_jmap').trigger('click');
$('#srv_setup_stepper_jmap_address').val(details.server);
$('#srv_setup_stepper_imap_hide_from_c_page').prop("checked", details.hide);
};
-var imap_smtp_edit_action = function(event) {
+var imap_smtp_edit_action = function (event) {
resetQuickSetupForm();
event.preventDefault();
Hm_Notices.hide(true);
@@ -1767,7 +1770,7 @@ var imap_smtp_edit_action = function(event) {
fillJmapData(details);
} else if ($(this).data('type') == 'imap') {
fillImapData(details);
- var smtpDetails = $('[data-type="smtp"][data-id="'+details.name+'"]');
+ var smtpDetails = $('[data-type="smtp"][data-id="' + details.name + '"]');
if (smtpDetails.length) {
fillSmtpData(smtpDetails.data('server-details'));
} else {
@@ -1775,7 +1778,7 @@ var imap_smtp_edit_action = function(event) {
}
} else {
fillSmtpData(details);
- var imapDetails = $('[data-type="imap"][data-id="'+details.name+'"]');
+ var imapDetails = $('[data-type="imap"][data-id="' + details.name + '"]');
if (imapDetails.length) {
fillImapData(imapDetails.data('server-details'));
} else {
@@ -1784,7 +1787,8 @@ var imap_smtp_edit_action = function(event) {
}
};
-var hasLeadingOrTrailingSpaces = function(str) {
+
+var hasLeadingOrTrailingSpaces = function (str) {
return str !== str.trim();
};
@@ -1792,8 +1796,8 @@ var hasLeadingOrTrailingSpaces = function(str) {
var Hm_Message_List = new Message_List();
function sortHandlerForMessageListAndSearchPage() {
- $('.combined_sort').on("change", function() { Hm_Message_List.sort($(this).val()); });
- $('.source_link').on("click", function() { $('.list_sources').toggle(); $('#list_controls_menu').hide(); return false; });
+ $('.combined_sort').on("change", function () { Hm_Message_List.sort($(this).val()); });
+ $('.source_link').on("click", function () { $('.list_sources').toggle(); $('#list_controls_menu').hide(); return false; });
if (getListPathParam() == 'unread' && $('.menu_unread > a').css('font-weight') == 'bold') {
$('.menu_unread > a').css('font-weight', 'normal');
Hm_Folders.save_folder_list();
@@ -1801,7 +1805,7 @@ function sortHandlerForMessageListAndSearchPage() {
}
/* executes on onload, has access to other module code */
-$(function() {
+$(function () {
/* Remove disabled attribute to send checkbox */
$('.save_settings').on("click", function (e) {
$('.general_setting input[type=checkbox]').each(function () {
@@ -1810,7 +1814,7 @@ $(function() {
}
});
})
- $('.reset_factory_button').on('click', function() { return hm_delete_prompt(); });
+ $('.reset_factory_button').on('click', function () { return hm_delete_prompt(); });
/* check for folder reload */
var reloaded = Hm_Folders.reload_folders();
@@ -1821,7 +1825,7 @@ $(function() {
/* fire up the job scheduler */
Hm_Timer.fire();
-
+
/* show any pending notices */
Hm_Utils.show_sys_messages();
@@ -1832,18 +1836,18 @@ $(function() {
hl_save_link();
if (hm_mailto()) {
- try { navigator.registerProtocolHandler("mailto", "?page=compose&compose_to=%s", "Cypht"); } catch(e) {}
+ try { navigator.registerProtocolHandler("mailto", "?page=compose&compose_to=%s", "Cypht"); } catch (e) { }
}
if (hm_mobile()) {
- swipe_event(document.body, function() { Hm_Folders.open_folder_list(); }, 'right');
- swipe_event(document.body, function() { Hm_Folders.hide_folder_list(); }, 'left');
+ swipe_event(document.body, function () { Hm_Folders.open_folder_list(); }, 'right');
+ swipe_event(document.body, function () { Hm_Folders.hide_folder_list(); }, 'left');
$('.list_controls.on_mobile').show();
$('.list_controls.no_mobile').hide();
} else {
$('.list_controls.on_mobile').hide();
}
- $('.offline').on("click", function() { Hm_Utils.test_connection(); });
+ $('.offline').on("click", function () { Hm_Utils.test_connection(); });
if (hm_check_dirty_flag()) {
$('form:not(.search_terms)').areYouSure();
@@ -1893,7 +1897,7 @@ function fixLtrInRtl() {
return []
}
- setTimeout(function(){
+ setTimeout(function () {
var elements = getElements()
for (var index = 0; index < elements.length; index++) {
if (isTextEnglish(elements[index].textContent)) {
@@ -1911,7 +1915,7 @@ function listControlsMenu() {
$('.list_sources').hide();
}
-var resetStepperButtons = function() {
+var resetStepperButtons = function () {
$('.step_config-actions button').removeAttr('disabled');
$('#stepper-action-finish').text($('#stepper-action-finish').text().slice(0, -3));
};
@@ -1948,14 +1952,14 @@ function submitSmtpImapServer() {
{ name: 'srv_setup_stepper_smtp_server_id', value: $('#srv_setup_stepper_smtp_server_id').val() }
];
- Hm_Ajax.request(requestData, function(res) {
+ Hm_Ajax.request(requestData, function (res) {
resetStepperButtons();
if (res.just_saved_credentials) {
if (res.imap_server_id) {
Hm_Ajax.request(
- [{'name': 'hm_ajax_hook', 'value': 'ajax_imap_accept_special_folders'},
- {'name': 'imap_server_id', value: res.imap_server_id},
- {'name': 'imap_service_name', value: res.imap_service_name}],
+ [{ 'name': 'hm_ajax_hook', 'value': 'ajax_imap_accept_special_folders' },
+ { 'name': 'imap_server_id', value: res.imap_server_id },
+ { 'name': 'imap_service_name', value: res.imap_service_name }],
function () {
resetQuickSetupForm();
Hm_Utils.redirect();
@@ -2000,23 +2004,23 @@ function resetQuickSetupForm() {
}
function handleCreateProfileCheckboxChange(checkbox) {
- if(checkbox.checked) {
- $(checkbox).closest('.form-check').next().show();
- }else{
- $(checkbox).closest('.form-check').next().hide();
+ if (checkbox.checked) {
+ $('#srv_setup_stepper_profile_bloc').show();
+ } else {
+ $('#srv_setup_stepper_profile_bloc').hide();
}
}
-function handleSieveStatusChange (checkbox) {
- if(checkbox.checked) {
+function handleSieveStatusChange(checkbox) {
+ if (checkbox.checked) {
$('#srv_setup_stepper_imap_sieve_host_bloc').show();
- }else{
+ } else {
$('#srv_setup_stepper_imap_sieve_host_bloc').hide();
}
}
function handleSmtpImapCheckboxChange(checkbox) {
if (checkbox.id === 'srv_setup_stepper_is_receiver') {
- if(checkbox.checked) {
+ if (checkbox.checked) {
$('#step_config-imap_bloc').show();
$('#step_config_combined_view').show();
$('#srv_setup_stepper_jmap_select_box').show();
@@ -2031,15 +2035,15 @@ function handleSmtpImapCheckboxChange(checkbox) {
if (checkbox.id === 'srv_setup_stepper_is_sender') {
console.log("checkbox.checked", checkbox.checked)
- if(checkbox.checked) $('#step_config-smtp_bloc').show();
+ if (checkbox.checked) $('#step_config-smtp_bloc').show();
else $('#step_config-smtp_bloc').hide();
}
if ($('#srv_setup_stepper_is_sender').prop('checked') && $('#srv_setup_stepper_is_receiver').prop('checked')) {
$('#srv_setup_stepper_profile_bloc').show();
$('#srv_setup_stepper_profile_checkbox_bloc').show();
-
- } else if(! $('#srv_setup_stepper_is_sender').prop('checked') || ! $('#srv_setup_stepper_is_receiver').prop('checked')) {
+
+ } else if (!$('#srv_setup_stepper_is_sender').prop('checked') || !$('#srv_setup_stepper_is_receiver').prop('checked')) {
$('#srv_setup_stepper_profile_bloc').hide();
$('#srv_setup_stepper_profile_checkbox_bloc').hide();
}
@@ -2049,7 +2053,7 @@ function handleJmapCheckboxChange(checkbox) {
if (checkbox.checked) {
$('#step_config-jmap_bloc').show();
$('#step_config-imap_bloc').hide();
- if (! $('#srv_setup_stepper_enable_sieve').prop('checked')) {
+ if (!$('#srv_setup_stepper_enable_sieve').prop('checked')) {
$('#srv_setup_stepper_imap_sieve_host_bloc').hide();
}
} else {
@@ -2060,9 +2064,9 @@ function handleJmapCheckboxChange(checkbox) {
function handleProviderChange(select) {
let providerKey = select.value;
- if(providerKey) {
+ if (providerKey) {
getServiceDetails(providerKey);
- }else{
+ } else {
$("#srv_setup_stepper_smtp_address").val('');
$("#srv_setup_stepper_smtp_port").val(465);
$("#srv_setup_stepper_imap_address").val('');
@@ -2076,13 +2080,13 @@ function setDefaultReplyTo(val) {
}
}
function display_config_step(stepNumber) {
- if(stepNumber === 2) {
+ if (stepNumber === 2) {
var isValid = true;
- [ {key: 'srv_setup_stepper_profile_name', value: $('#srv_setup_stepper_profile_name').val()},
- {key: 'srv_setup_stepper_email', value: $('#srv_setup_stepper_email').val()},
- {key: 'srv_setup_stepper_password', value: $('#srv_setup_stepper_password').val()}].forEach((item) => {
+ [{ key: 'srv_setup_stepper_profile_name', value: $('#srv_setup_stepper_profile_name').val() },
+ { key: 'srv_setup_stepper_email', value: $('#srv_setup_stepper_email').val() },
+ { key: 'srv_setup_stepper_password', value: $('#srv_setup_stepper_password').val() }].forEach((item) => {
if (!item.value) {
if (item.key == 'srv_setup_stepper_password' && ($('#srv_setup_stepper_imap_server_id').val() || $('#srv_setup_stepper_smtp_server_id').val())) {
$(`#${item.key}-error`).text('');
@@ -2090,7 +2094,7 @@ function display_config_step(stepNumber) {
$(`#${item.key}-error`).text('Required');
isValid = false;
}
-
+
} else {
$(`#${item.key}-error`).text('');
}
@@ -2105,46 +2109,46 @@ function display_config_step(stepNumber) {
setDefaultReplyTo($('#srv_setup_stepper_email').val());
}
- if(stepNumber === 3) {
+ if (stepNumber === 3) {
var requiredFields = [];
var isValid = true;
- if(!$('#srv_setup_stepper_is_sender').is(':checked') && !$('#srv_setup_stepper_is_receiver').is(':checked')){
+ if (!$('#srv_setup_stepper_is_sender').is(':checked') && !$('#srv_setup_stepper_is_receiver').is(':checked')) {
$('#srv_setup_stepper_serve_type-error').text('Required');
return;
}
- if($('#srv_setup_stepper_is_sender').is(':checked') &&
+ if ($('#srv_setup_stepper_is_sender').is(':checked') &&
$('#srv_setup_stepper_is_receiver').is(':checked') &&
- $('#srv_setup_stepper_only_jmap').is(':checked')){
+ $('#srv_setup_stepper_only_jmap').is(':checked')) {
requiredFields.push(
- {key: 'srv_setup_stepper_jmap_address', value: $('#srv_setup_stepper_jmap_address').val()},
+ { key: 'srv_setup_stepper_jmap_address', value: $('#srv_setup_stepper_jmap_address').val() },
)
- }else {
- if($('#srv_setup_stepper_is_sender').is(':checked')){
+ } else {
+ if ($('#srv_setup_stepper_is_sender').is(':checked')) {
requiredFields.push(
- {key: 'srv_setup_stepper_smtp_address', value: $('#srv_setup_stepper_smtp_address').val()},
- {key: 'srv_setup_stepper_smtp_port', value: $('#srv_setup_stepper_smtp_port').val()},
+ { key: 'srv_setup_stepper_smtp_address', value: $('#srv_setup_stepper_smtp_address').val() },
+ { key: 'srv_setup_stepper_smtp_port', value: $('#srv_setup_stepper_smtp_port').val() },
)
}
- if($('#srv_setup_stepper_is_receiver').is(':checked')) {
+ if ($('#srv_setup_stepper_is_receiver').is(':checked')) {
requiredFields.push(
- {key: 'srv_setup_stepper_imap_address', value: $('#srv_setup_stepper_imap_address').val()},
- {key: 'srv_setup_stepper_imap_port', value: $('#srv_setup_stepper_imap_port').val()},
+ { key: 'srv_setup_stepper_imap_address', value: $('#srv_setup_stepper_imap_address').val() },
+ { key: 'srv_setup_stepper_imap_port', value: $('#srv_setup_stepper_imap_port').val() },
)
}
}
- if($('#srv_setup_stepper_enable_sieve').is(':checked')) {
+ if ($('#srv_setup_stepper_enable_sieve').is(':checked')) {
requiredFields.push(
- {key: 'srv_setup_stepper_imap_sieve_host', value: $('#srv_setup_stepper_imap_sieve_host').val()},
- {key: 'srv_setup_stepper_imap_sieve_mode_tls', value: $('#srv_setup_stepper_imap_sieve_mode_tls').val()},
+ { key: 'srv_setup_stepper_imap_sieve_host', value: $('#srv_setup_stepper_imap_sieve_host').val() },
+ { key: 'srv_setup_stepper_imap_sieve_mode_tls', value: $('#srv_setup_stepper_imap_sieve_mode_tls').val() },
)
}
requiredFields.forEach((item) => {
- if(!item.value) {
+ if (!item.value) {
$(`#${item.key}-error`).text('Required');
isValid = false;
}
@@ -2152,7 +2156,7 @@ function display_config_step(stepNumber) {
})
- if(!isValid) return
+ if (!isValid) return
submitSmtpImapServer();
return
@@ -2168,32 +2172,32 @@ function display_config_step(stepNumber) {
if (selectedStep) {
selectedStep.style.display = 'block';
- if(stepNumber === 0) $('.srv_setup_stepper_btn').show();
+ if (stepNumber === 0) $('.srv_setup_stepper_btn').show();
}
}
-function getServiceDetails(providerKey){
- if(providerKey) {
+function getServiceDetails(providerKey) {
+ if (providerKey) {
$("#srv_setup_stepper_provider").val(providerKey);
Hm_Ajax.request(
[
- {'name': 'hm_ajax_hook', 'value': 'ajax_get_nux_service_details'},
- {'name': 'nux_service', 'value': providerKey},],
- function(res) {
- if(res.service_details){
+ { 'name': 'hm_ajax_hook', 'value': 'ajax_get_nux_service_details' },
+ { 'name': 'nux_service', 'value': providerKey },],
+ function (res) {
+ if (res.service_details) {
let serverConfig = JSON.parse(res.service_details)
$("#srv_setup_stepper_smtp_address").val(serverConfig.smtp.server);
$("#srv_setup_stepper_smtp_port").val(serverConfig.smtp.port);
- if(serverConfig.smtp.tls)$("input[name='srv_setup_stepper_smtp_tls'][value='true']").prop("checked", true);
+ if (serverConfig.smtp.tls) $("input[name='srv_setup_stepper_smtp_tls'][value='true']").prop("checked", true);
else $("input[name='srv_setup_stepper_smtp_tls'][value='false']").prop("checked", true);
$("#srv_setup_stepper_imap_address").val(serverConfig.server);
$("#srv_setup_stepper_imap_port").val(serverConfig.port);
- if(serverConfig.tls)$("input[name='srv_setup_stepper_imap_tls'][value='true']").prop("checked", true);
+ if (serverConfig.tls) $("input[name='srv_setup_stepper_imap_tls'][value='true']").prop("checked", true);
else $("input[name='srv_setup_stepper_imap_tls'][value='false']").prop("checked", true);
if (serverConfig.hasOwnProperty('sieve')) {
@@ -2245,7 +2249,7 @@ function getEmailProviderKey(email) {
const emailParts = email.split("@");
- if(emailParts.length !== 2) return "";
+ if (emailParts.length !== 2) return "";
const provider = emailParts[1].toLowerCase();
@@ -2374,14 +2378,14 @@ const handleExternalResources = (inline) => {
};
const observeMessageTextMutationAndHandleExternalResources = (inline) => {
- const message = document.querySelector('.msg_text');
+ const message = document.querySelector('.msg_text');
if (message) {
new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach(function (node) {
if (node.classList.contains('msg_text_inner')) {
- handleExternalResources(inline);
+ handleExternalResources(inline);
}
});
}
@@ -2391,3 +2395,55 @@ const observeMessageTextMutationAndHandleExternalResources = (inline) => {
});
}
};
+
+function setupActionSchedule(callback) {
+ $(document).on('click', '.nexter_date_picker', function (e) {
+ document.querySelector('.nexter_input_date').showPicker();
+ });
+ $(document).on('click', '.nexter_date_helper', function (e) {
+ e.preventDefault();
+ $('.nexter_input').val($(this).attr('data-value')).trigger('change');
+ });
+ $(document).on('input', '.nexter_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()) {
+ $('.nexter_date_picker').css('border', '1px solid red');
+ } else {
+ $('.nexter_date_picker').css({ 'border': 'unset', 'border-top': '1px solid #ddd' });
+ }
+ });
+ $(document).on('change', '.nexter_input_date', function (e) {
+ if ($(this).val() && new Date().getTime() < new Date($(this).val()).getTime()) {
+ $('.nexter_input').val($(this).val()).trigger('change');
+ }
+ });
+ $(document).on('change', '.nexter_input', callback);
+}
+
+function setupActionSnooze(callback) {
+ $(document).on('click', '.nexter_date_picker_snooze', function (e) {
+ document.querySelector('.nexter_input_date_snooze').showPicker();
+ });
+ $(document).on('click', '.nexter_date_helper_snooze', function (e) {
+ e.preventDefault();
+ $('.nexter_input_snooze').val($(this).attr('data-value')).trigger('change');
+ });
+ $(document).on('input', '.nexter_input_date_snooze', 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()) {
+ $('.nexter_date_picker_snooze').css('border', '1px solid red');
+ } else {
+ $('.nexter_date_picker_snooze').css({ 'border': 'unset', 'border-top': '1px solid #ddd' });
+ }
+ });
+ $(document).on('change', '.nexter_input_date_snooze', function (e) {
+ if ($(this).val() && new Date().getTime() < new Date($(this).val()).getTime()) {
+ $('.nexter_input_snooze').val($(this).val()).trigger('change');
+ }
+ });
+ $(document).on('change', '.nexter_input_snooze', callback);
+}
diff --git a/modules/imap/functions.php b/modules/imap/functions.php
index 524a585016..c6d2d60098 100644
--- a/modules/imap/functions.php
+++ b/modules/imap/functions.php
@@ -248,10 +248,14 @@ function format_imap_message_list($msg_list, $output_module, $parent_list=false,
$nofrom = ' nofrom';
}
$is_snoozed = !empty($msg['x_snoozed']) && hex2bin($msg['folder']) == 'Snoozed';
+ $is_scheduled = !empty($msg['x_schedule']) && hex2bin($msg['folder']) == 'Scheduled';
if ($is_snoozed) {
- $snooze_header = parse_snooze_header('X-Snoozed: '.$msg['x_snoozed']);
+ $snooze_header = parse_nexter_header('X-Snoozed: '.$msg['x_snoozed'], 'X-Snoozed');
$date = $snooze_header['until'];
$timestamp = strtotime($date);
+ } elseif ($is_scheduled) {
+ $date = $msg['x_schedule'];
+ $timestamp = strtotime($date);
} else {
if ($list_sort == 'date') {
$date_field = 'date';
@@ -326,7 +330,7 @@ function format_imap_message_list($msg_list, $output_module, $parent_list=false,
array('safe_output_callback', 'source', $source, $icon),
array('safe_output_callback', 'from'.$nofrom, $from, null, str_replace(array($from, '<', '>'), '', $msg['from'])),
array('subject_callback', $subject, $url, $flags, null, $preview_msg),
- array('date_callback', $date, $timestamp, $is_snoozed),
+ array('date_callback', $date, $timestamp, $is_snoozed || $is_scheduled),
array('icon_callback', $flags)
),
$id,
@@ -1324,7 +1328,7 @@ function snooze_message($mailbox, $msg_id, $folder, $snooze_tag) {
preg_match("/^X-Snoozed:.*(\r?\n[ \t]+.*)*\r?\n?/im", $msg, $matches);
if (count($matches)) {
$msg = str_replace($matches[0], '', $msg);
- $old_folder = parse_snooze_header($matches[0])['from'];
+ $old_folder = parse_nexter_header($matches[0], 'X-Snoozed')['from'];
}
if ($snooze_tag) {
$from = $old_folder ?? $folder;
@@ -1351,7 +1355,7 @@ function snooze_message($mailbox, $msg_id, $folder, $snooze_tag) {
}
}
} else {
- $snooze_headers = parse_snooze_header($matches[0]);
+ $snooze_headers = parse_nexter_header($matches[0], 'X-Snoozed');
$original_folder = $snooze_headers['from'];
if ($mailbox->store_message($original_folder, $msg)) {
$deleteResult = $mailbox->message_action($snooze_folder, 'DELETE', array($msg_id));
@@ -1438,21 +1442,21 @@ function snooze_formats() {
*/
if (!hm_exists('snooze_dropdown')) {
function snooze_dropdown($output, $unsnooze = false) {
- $values = snooze_formats();
+ $values = nexter_formats();
$txt = '
-
-
';
@@ -1585,3 +1589,42 @@ function connect_to_imap_server($address, $name, $port, $user, $pass, $tls, $ima
}
}
}
+
+if (!hm_exists('save_sent_msg')) {
+function save_sent_msg($handler, $imap_id, $imap, $imap_details, $msg, $msg_id, $show_errors = true) {
+ $specials = get_special_folders($handler, $imap_id);
+ if (array_key_exists('sent', $specials) && $specials['sent']) {
+ $sent_folder = $specials['sent'];
+ }
+
+ if (!$sent_folder) {
+ $auto_sent = $imap->get_special_use_mailboxes('sent');
+ if (!array_key_exists('sent', $auto_sent)) {
+ return;
+ }
+ $sent_folder = $auto_sent['sent'];
+ }
+ if (!$sent_folder) {
+ Hm_Debug::add(sprintf("Unable to save sent message, no sent folder for IMAP %s", $imap_details['server']));
+ }
+ $uid = null;
+ if ($sent_folder) {
+ Hm_Debug::add(sprintf("Attempting to save sent message for IMAP server %s in folder %s", $imap_details['server'], $sent_folder));
+ if ($imap->append_start($sent_folder, strlen($msg), true)) {
+ $imap->append_feed($msg."\r\n");
+ if (!$imap->append_end() && $show_errors) {
+ Hm_Msgs::add('ERRAn error occurred saving the sent message');
+ }
+ }
+
+ $mailbox_page = $imap->get_mailbox_page($sent_folder, 'ARRIVAL', true, 'ALL', 0, 10);
+ foreach ($mailbox_page[1] as $mail) {
+ $msg_header = $imap->get_message_headers($mail['uid']);
+ if ($msg_header['Message-Id'] === $msg_id) {
+ $uid = $mail['uid'];
+ break;
+ }
+ }
+ }
+ return $uid;
+}}
diff --git a/modules/imap/handler_modules.php b/modules/imap/handler_modules.php
index a44ebfd461..c27fce69a5 100644
--- a/modules/imap/handler_modules.php
+++ b/modules/imap/handler_modules.php
@@ -361,7 +361,10 @@ public function process() {
break;
}
}
- if ($uid && $this->user_config->get('review_sent_email_setting', true)) {
+ }
+ $uid = save_sent_msg($this, $imap_id, $imap, $imap_details, $msg, $mime->get_headers()['Message-Id']);
+ if ($uid) {
+ if ($uid && $this->user_config->get('review_sent_email_setting', false)) {
$this->out('redirect_url', '?page=message&uid='.$uid.'&list_path=imap_'.$imap_id.'_'.bin2hex($sent_folder));
}
}
@@ -1042,7 +1045,7 @@ public function process() {
$snooze_tag = null;
if ($form['imap_snooze_until'] != 'unsnooze') {
$at = date('D, d M Y H:i:s O');
- $until = get_snooze_date($form['imap_snooze_until']);
+ $until = get_scheduled_date($form['imap_snooze_until']);
$snooze_tag = "X-Snoozed: at $at; until $until";
}
$ids = explode(',', $form['imap_snooze_ids']);
@@ -1093,7 +1096,7 @@ public function process() {
$msg_headers = $mailbox->get_message_headers($folder, $msg['uid']);
if (isset($msg_headers['X-Snoozed'])) {
try {
- $snooze_headers = parse_snooze_header($msg_headers['X-Snoozed']);
+ $snooze_headers = parse_nexter_header($msg_headers['X-Snoozed'], 'X-Snoozed');
if (new DateTime($snooze_headers['until']) <= new DateTime()) {
snooze_message($mailbox, $msg['uid'], $folder, null);
}
diff --git a/modules/imap/hm-imap.php b/modules/imap/hm-imap.php
index 3e8759c32b..3574666aba 100644
--- a/modules/imap/hm-imap.php
+++ b/modules/imap/hm-imap.php
@@ -899,7 +899,7 @@ public function get_message_list($uids, $raw=false, $include_content_body = fals
if ($this->is_supported( 'X-GM-EXT-1' )) {
$command .= 'X-GM-MSGID X-GM-THRID X-GM-LABELS ';
}
- $command .= "BODY.PEEK[HEADER.FIELDS (SUBJECT X-AUTO-BCC FROM DATE CONTENT-TYPE X-PRIORITY TO LIST-ARCHIVE REFERENCES MESSAGE-ID X-SNOOZED)]";
+ $command .= "BODY.PEEK[HEADER.FIELDS (SUBJECT X-AUTO-BCC FROM DATE CONTENT-TYPE X-PRIORITY TO LIST-ARCHIVE REFERENCES MESSAGE-ID X-SNOOZED X-SCHEDULE X-PROFILE-ID X-DELIVERY)])";
if ($include_content_body) {
$command .= " BODY.PEEK[0.1]";
}
@@ -913,8 +913,8 @@ public function get_message_list($uids, $raw=false, $include_content_body = fals
$res = $this->get_response(false, true);
$status = $this->check_response($res, true);
$tags = array('X-GM-MSGID' => 'google_msg_id', 'X-GM-THRID' => 'google_thread_id', 'X-GM-LABELS' => 'google_labels', 'UID' => 'uid', 'FLAGS' => 'flags', 'RFC822.SIZE' => 'size', 'INTERNALDATE' => 'internal_date');
- $junk = array('X-AUTO-BCC', 'MESSAGE-ID', 'REFERENCES', 'X-SNOOZED', 'LIST-ARCHIVE', 'SUBJECT', 'FROM', 'CONTENT-TYPE', 'TO', '(', ')', ']', 'X-PRIORITY', 'DATE');
- $flds = array('x-auto-bcc' => 'x_auto_bcc', 'message-id' => 'message_id', 'references' => 'references', 'x-snoozed' => 'x_snoozed', 'list-archive' => 'list_archive', 'date' => 'date', 'from' => 'from', 'to' => 'to', 'subject' => 'subject', 'content-type' => 'content_type', 'x-priority' => 'x_priority', 'body' => 'content_body');
+ $junk = array('X-AUTO-BCC', 'MESSAGE-ID', 'REFERENCES', 'X-SNOOZED', 'X-SCHEDULE', 'X-PROFILE-ID', 'X-DELIVERY', 'LIST-ARCHIVE', 'SUBJECT', 'FROM', 'CONTENT-TYPE', 'TO', '(', ')', ']', 'X-PRIORITY', 'DATE');
+ $flds = array('x-auto-bcc' => 'x_auto_bcc', 'message-id' => 'message_id', 'references' => 'references', 'x-snoozed' => 'x_snoozed', 'x-schedule' => 'x_schedule', 'x-profile-id' => 'x_profile_id', 'x-delivery' => 'x_delivery', 'list-archive' => 'list_archive', 'date' => 'date', 'from' => 'from', 'to' => 'to', 'subject' => 'subject', 'content-type' => 'content_type', 'x-priority' => 'x_priority');
$headers = array();
foreach ($res as $n => $vals) {
@@ -937,6 +937,9 @@ public function get_message_list($uids, $raw=false, $include_content_body = fals
$google_labels = '';
$x_auto_bcc = '';
$x_snoozed = '';
+ $x_schedule = '';
+ $x_profile_id = '';
+ $x_delivery = '';
$count = count($vals);
for ($i=0;$i<$count;$i++) {
if ($vals[$i] == 'BODY[HEADER.FIELDS') {
@@ -999,8 +1002,7 @@ public function get_message_list($uids, $raw=false, $include_content_body = fals
'timestamp' => time(), 'charset' => $cset, 'x-priority' => $x_priority, 'google_msg_id' => $google_msg_id,
'google_thread_id' => $google_thread_id, 'google_labels' => $google_labels, 'list_archive' => $list_archive,
'references' => $references, 'message_id' => $message_id, 'x_auto_bcc' => $x_auto_bcc,
- 'x_snoozed' => $x_snoozed);
- $headers[$uid]['preview_msg'] = $flds['body'] != "content_body" ? $flds['body'] : "";
+ 'x_snoozed' => $x_snoozed, 'x_schedule' => $x_schedule, 'x_profile_id' => $x_profile_id, 'x_delivery' => $x_delivery);
if ($raw) {
$headers[$uid] = array_map('trim', $headers[$uid]);
diff --git a/modules/imap/js_modules/route_handlers.js b/modules/imap/js_modules/route_handlers.js
index 6b98603913..2d2f7bd4f3 100644
--- a/modules/imap/js_modules/route_handlers.js
+++ b/modules/imap/js_modules/route_handlers.js
@@ -4,10 +4,14 @@ function applyImapMessageListPageHandlers(routeParams) {
imap_setup_snooze();
imap_setup_tags();
+ Hm_Message_List.set_row_events();
+
+ processNextActionDate();
+
if (window.inlineMessageMessageListAndSearchPageHandler) inlineMessageMessageListAndSearchPageHandler(routeParams);
if (window.wpMessageListPageHandler) wpMessageListPageHandler(routeParams);
- return async function() {
+ return async function () {
const [refreshIntervalId, abortController] = await setupPageResult;
abortController.abort();
clearInterval(refreshIntervalId);
@@ -33,4 +37,4 @@ function applyImapMessageContentPageHandlers(routeParams) {
if (window.pgpMessageContentPageHandler) pgpMessageContentPageHandler();
if (window.wpMessageContentPageHandler) wpMessageContentPageHandler(routeParams);
-}
\ No newline at end of file
+}
diff --git a/modules/imap/js_modules/utils/handleNexterDateAction.js b/modules/imap/js_modules/utils/handleNexterDateAction.js
new file mode 100644
index 0000000000..02c303a9fc
--- /dev/null
+++ b/modules/imap/js_modules/utils/handleNexterDateAction.js
@@ -0,0 +1,71 @@
+function processNextActionDate(e) {
+ let isReloading = false;
+
+ let reload_and_redirect = async function () {
+ if (isReloading) {
+ return;
+ }
+ isReloading = true;
+
+ showRoutingToast();
+
+ try {
+ Hm_Folders.reload_folders(true);
+ let path = getListPathParam();
+ await navigate(`?page=message_list&list_path=${path}`);
+ } finally {
+ hideRoutingToast();
+ isReloading = false;
+ }
+ };
+
+
+
+ let collectCheckedIds = function () {
+ let ids = [];
+ $('input[type=checkbox]').each(function () {
+ if (this.checked && this.id.search('imap') !== -1) {
+ let parts = this.id.split('_');
+ ids.push(parts[1] + '_' + parts[2] + '_' + parts[3]);
+ }
+ });
+ if (ids.length === 0) {
+ return;
+ }
+ return ids;
+ };
+
+ setupActionSchedule(function () {
+ let ids = collectCheckedIds();
+
+ Hm_Ajax.request(
+ [
+ { 'name': 'hm_ajax_hook', 'value': 'ajax_re_schedule_message_sending' },
+ { 'name': 'scheduled_msg_ids', 'value': ids },
+ { 'name': 'schedule_date', 'value': $(this).val() }
+ ],
+ function (res) {
+ if (res.scheduled_msg_count > 0) {
+ reload_and_redirect();
+ }
+ }
+ );
+ });
+
+ setupActionSnooze(function () {
+ let ids = collectCheckedIds();
+
+ 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) {
+ reload_and_redirect();
+ }
+ }
+ );
+ });
+}
\ No newline at end of file
diff --git a/modules/imap/output_modules.php b/modules/imap/output_modules.php
index c72420fc6c..538f05fc04 100644
--- a/modules/imap/output_modules.php
+++ b/modules/imap/output_modules.php
@@ -206,9 +206,9 @@ protected function output() {
$txt .= $this->html_safe($value).'';
}
elseif ($fld == 'x-snoozed') {
- $snooze_header = parse_snooze_header($value);
+ $snooze_header = parse_nexter_header($value, 'X-Snoozed');
$txt .= '';
+ $txt .= $this->trans('Snoozed').'
'.$this->trans('Until').' '.$this->html_safe($snooze_header['until']).' Unsnooze ';
}
elseif ($fld == 'date') {
try {
@@ -390,6 +390,9 @@ protected function output() {
if($this->get('tags')){
$txt .= ' | '. tags_dropdown($this, $headers);
}
+ if (isset($headers['X-Schedule'])) {
+ $txt .= ' | ' . schedule_dropdown($this, true);
+ }
$is_draft = isset($headers['Flags']) && mb_stristr($headers['Flags'], 'draft');
if ($this->get('sieve_filters_enabled') && !$is_draft) {
diff --git a/modules/imap/site.css b/modules/imap/site.css
index f291345bab..db8576ec53 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 c751439a6b..dc6a9e7169 100644
--- a/modules/imap/site.js
+++ b/modules/imap/site.js
@@ -1221,6 +1221,7 @@ $(function() {
setTimeout(search_selected_for_imap, 100);
});
+
if (hm_is_logged()) {
imap_unsnooze_messages();
setInterval(imap_unsnooze_messages, 60000);
diff --git a/modules/profiles/functions.php b/modules/profiles/functions.php
index dcfc100056..d75922ab6a 100644
--- a/modules/profiles/functions.php
+++ b/modules/profiles/functions.php
@@ -12,8 +12,8 @@ function add_profile($name, $signature, $reply_to, $is_default, $email, $server,
'replyto' => $reply_to,
'default' => $is_default,
'address' => $email,
- 'server' => $server,
- 'user' => $user,
+ 'server' => $imap_server_id,
+ 'user' => $email,
'type' => 'imap'
);
$id = Hm_Profiles::add($profile);
diff --git a/modules/profiles/hm-profiles.php b/modules/profiles/hm-profiles.php
index 16997e0582..046d6e6648 100644
--- a/modules/profiles/hm-profiles.php
+++ b/modules/profiles/hm-profiles.php
@@ -109,4 +109,19 @@ public static function loadLegacy($hmod) {
}
}
}
+
+ /**
+ * @param string $field The name of the field to search within.
+ * @param mixed $value The value to search for within the specified field.
+ * @return array An array containing profiles that match the search criteria.
+ */
+ public static function search($field, $value) {
+ $res = array();
+ foreach (self::getAll() as $profile) {
+ if (!empty($profile[$field]) && $profile[$field] == $value) {
+ $res[] = $profile;
+ }
+ }
+ return $res;
+ }
}
diff --git a/modules/smtp/functions.php b/modules/smtp/functions.php
index 68a8db3b16..742068cc49 100644
--- a/modules/smtp/functions.php
+++ b/modules/smtp/functions.php
@@ -61,3 +61,109 @@ function get_reply_type($request) {
return false;
}
}
+
+/**
+ * @subpackage smtp/functions
+ */
+if (!hm_exists('send_scheduled_message')) {
+function send_scheduled_message($handler, $imap, $msg_id, $server_id, $send_now = false) {
+ $msg_headers = $imap->get_message_headers($msg_id);
+ $imap_details = Hm_IMAP_List::dump($server_id);
+ if (empty($imap_details)) {
+ return false;
+ }
+
+ try {
+ if (empty($msg_headers['X-Schedule'])) {
+ return false;
+ }
+
+ if (new DateTime($msg_headers['X-Schedule']) <= new DateTime() || $send_now) {
+ $profile = Hm_Profiles::get($msg_headers['X-Profile-ID']);
+ if (!$profile) {
+ $profiles = Hm_Profiles::search('server', $imap_details['server']);
+
+ if (!$profiles) {
+ Hm_Debug::add(sprintf('ERRCannot find profiles corresponding with IMAP server: %s', $imap_details['server']));
+ return false;
+ }
+ $profile = $profiles[0];
+ }
+
+ $smtp = Hm_SMTP_List::connect($profile['smtp_id'], false);
+
+ if (smtp_authed($smtp)) {
+ if (isset($msg_headers['X-Delivery'])) {
+ $from_params = 'RET=HDRS';
+ $recipients_params = 'NOTIFY=SUCCESS,FAILURE';
+ } else {
+ $from_params = '';
+ $recipients_params = '';
+ }
+
+ $recipients = [];
+ foreach (['To', 'Cc', 'Bcc'] as $fld) {
+ if (array_key_exists($fld, $msg_headers)) {
+ $recipients = array_merge($recipients, Hm_MIME_Msg::find_addresses($msg_headers[$fld]));
+ }
+ }
+
+ $msg_content = $imap->get_message_content($msg_id, 0);
+ $from = process_address_fld($msg_headers['From']);
+
+ $err_msg = $smtp->send_message($from[0]['email'], $recipients, $msg_content, $from_params, $recipients_params);
+
+ if (!$err_msg) {
+ if ($imap->message_action('DELETE', [$msg_id])) {
+ $imap->message_action('EXPUNGE', [$msg_id]);
+ }
+ save_sent_msg($handler, $server_id, $imap, $imap_details, $msg_content, $msg_id, false);
+ return true;
+ }
+ }
+ }
+ } catch (Exception $e) {
+ Hm_Debug::add(sprintf('ERRCannot send message: %s', $msg_headers['subject']));
+ }
+ return false;
+}}
+
+/**
+ * @subpackage smtp/functions
+ */
+if (!hm_exists('reschedule_message_sending')) {
+function reschedule_message_sending($handler, $imap, $msg_id, $folder, $new_date, $server_id) {
+ if (!$imap->select_mailbox($folder)) {
+ return;
+ }
+ if ($new_date == 'now') {
+ return send_scheduled_message($handler, $imap, $msg_id, $server_id, true);
+ }
+ $msg = $imap->get_message_content($msg_id, 0);
+ $new_date = get_scheduled_date($new_date);
+ preg_match("/^X-Schedule:.*(\r?\n[ \t]+.*)*\r?\n?/im", $msg, $matches);
+ if (count($matches)) {
+ $msg = str_replace($matches[0], "X-Schedule: {$new_date}\n", $msg);
+ } else {
+ return;
+ }
+ $msg = str_replace("\r\n", "\n", $msg);
+ $msg = str_replace("\n", "\r\n", $msg);
+ $msg = rtrim($msg)."\r\n";
+
+ $schedule_folder = 'Scheduled';
+ if (!count($imap->get_mailbox_status($schedule_folder))) {
+ return;
+ }
+ $res = false;
+ if ($imap->select_mailbox($schedule_folder) && $imap->append_start($schedule_folder, strlen($msg))) {
+ $imap->append_feed($msg."\r\n");
+ if ($imap->append_end()) {
+ if ($imap->select_mailbox($folder) && $imap->message_action('DELETE', array($msg_id))) {
+ $imap->message_action('EXPUNGE', array($msg_id));
+ $res = true;
+ }
+ }
+ }
+ return $res;
+}}
diff --git a/modules/smtp/hm-mime-message.php b/modules/smtp/hm-mime-message.php
index 1b775e0941..64cfe7b9dc 100644
--- a/modules/smtp/hm-mime-message.php
+++ b/modules/smtp/hm-mime-message.php
@@ -21,10 +21,15 @@ 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='', $delivery_receipt='', $schedule='', $profile_id = '') {
if ($cc) {
$this->headers['Cc'] = $cc;
}
+ if ($schedule) {
+ $this->headers['X-Schedule'] = $schedule;
+ $this->headers['X-Profile-ID'] = $profile_id;
+ }
+
if ($in_reply_to_id) {
$this->headers['In-Reply-To'] = $in_reply_to_id;
}
@@ -41,6 +46,9 @@ function __construct($to, $subject, $body, $from, $html=false, $cc='', $bcc='',
else {
$this->headers['Reply-To'] = $from;
}
+ if ($delivery_receipt) {
+ $this->headers['X-Delivery'] = $delivery_receipt;
+ }
$this->headers['To'] = $to;
$this->headers['Subject'] = html_entity_decode($subject, ENT_QUOTES);
$this->headers['Date'] = date('r');
@@ -190,7 +198,7 @@ function prep_fld($val, $name) {
return $this->encode_fld($val);
}
- function find_addresses($str) {
+ static function find_addresses($str) {
$res = array();
foreach (process_address_fld($str) as $vals) {
$res[] = $vals['email'];
@@ -210,7 +218,7 @@ function get_recipient_addresses() {
else {
continue;
}
- $res = array_merge($res, $this->find_addresses($v));
+ $res = array_merge($res, self::find_addresses($v));
}
return $res;
}
diff --git a/modules/smtp/js_modules/route_handlers.js b/modules/smtp/js_modules/route_handlers.js
index 7849599571..1f6a5692b5 100644
--- a/modules/smtp/js_modules/route_handlers.js
+++ b/modules/smtp/js_modules/route_handlers.js
@@ -2,18 +2,28 @@
function applyComposePageHandlers() {
init_resumable_upload()
+ let isScheduledMode = null;
+
+ setupActionSchedule(function () {
+ let schedule = $('.nexter_input').val();
+ $('.smtp_send_placeholder').trigger('click');
+
+ save_compose_state(false, true, schedule);
+ isScheduledMode = schedule;
+ });
+
if (window.HTMLEditor) {
useKindEditor();
}
var interval = Hm_Utils.get_from_global('compose_save_interval', 30);
- Hm_Timer.add_job(function() { save_compose_state(); }, interval, true);
- $('.draft_title').on("click", function() { $('.draft_list').toggle(); });
- $('.toggle_recipients').on("click", function() { return toggle_recip_flds(); });
+ Hm_Timer.add_job(function () { save_compose_state(); }, interval, true);
+ $('.draft_title').on("click", function () { $('.draft_list').toggle(); });
+ $('.toggle_recipients').on("click", function () { return toggle_recip_flds(); });
$('.smtp_reset').on("click", reset_smtp_form);
- $('.delete_draft').on("click", function() { smtp_delete_draft($(this).data('id')); });
- $('.smtp_save').on("click", function() { save_compose_state(false, true); });
- $('.smtp_send_archive').on("click", function() { send_archive(false, true); });
+ $('.delete_draft').on("click", function () { smtp_delete_draft($(this).data('id')); });
+ $('.smtp_save').on("click", function () { save_compose_state(false, true); });
+ $('.smtp_send_archive').on("click", function () { send_archive(false, true); });
const modal = new Hm_Modal({
modalId: 'emptySubjectBodyModal',
@@ -85,7 +95,7 @@ function applyComposePageHandlers() {
========================================
*/
function showModal() {
- if (! modal.modalContent.html()) {
+ if (!modal.modalContent.html()) {
modal.addFooterBtn(hm_trans('Send anyway'), 'btn-warning', handleSendAnyway);
if (showBtnSendAnywayDontWarnFuture) {
modal.addFooterBtn(hm_trans("Send anyway and don't warn in the future"), 'btn-warning', handleSendAnywayAndDontWarnMe);
@@ -99,26 +109,26 @@ function applyComposePageHandlers() {
return new Promise((resolve) => {
const checkValue = () => {
if ($(selector).val() !== targetValue) {
- resolve();
+ resolve();
} else {
- setTimeout(checkValue, 100);
+ setTimeout(checkValue, 100);
}
};
- checkValue();
+ checkValue();
});
}
async function handleSendAnyway() {
if ($('.compose_draft_id').val() == '0') {
- Hm_Notices.show([hm_trans('Please wait, sending message...')]);
- await waitForValueChange('.compose_draft_id', '0');
+ Hm_Notices.show([hm_trans('Please wait, sending message...')]);
+ await waitForValueChange('.compose_draft_id', '0');
}
-
-
if (handleMissingAttachment()) {
- document.getElementsByClassName("smtp_send")[0].click();
+ if (isScheduledMode == null) {
+ document.getElementsByClassName("smtp_send")[0].click();
+ }
} else {
e.preventDefault();
}
@@ -162,53 +172,53 @@ function applyComposePageHandlers() {
return true;
}
});
- $('.compose_form').on('submit', function() {
+ $('.compose_form').on('submit', function () {
process_compose_form();
});
if ($('.compose_cc').val() || $('.compose_bcc').val()) {
toggle_recip_flds();
}
if (window.location.href.search('&reply=1') !== -1 || window.location.href.search('&reply_all=1') !== -1) {
- replace_cursor_positon ($('textarea[name="compose_body"]'));
+ replace_cursor_positon($('textarea[name="compose_body"]'));
}
if (window.location.href.search('&forward=1') !== -1) {
- setTimeout(function() {
+ setTimeout(function () {
save_compose_state();
}, 100);
}
if ($('.sys_messages').text() != 'Message Sent') {
get_smtp_profile($('.compose_server').val());
}
- $('.compose_server').on('change', function() {
+ $('.compose_server').on('change', function () {
get_smtp_profile($('.compose_server').val());
});
- if($('.compose_attach_button').attr('disabled') == 'disabled'){
+ if ($('.compose_attach_button').attr('disabled') == 'disabled') {
check_attachment_dir_access();
};
$('.compose_container').attr('ondrop', 'move_recipient_to_section(event)').attr('ondragover', 'allow_drop(event)');
- $('.compose_to, .compose_cc, .compose_bcc').on('keypress', function(e) {
- if(e.which == 13) {
+ $('.compose_to, .compose_cc, .compose_bcc').on('keypress', function (e) {
+ if (e.which == 13) {
e.preventDefault();
text_to_bubbles(this);
}
});
- $('.compose_to, .compose_cc, .compose_bcc').on('blur', function(e) {
+ $('.compose_to, .compose_cc, .compose_bcc').on('blur', function (e) {
e.preventDefault();
text_to_bubbles(this);
});
- $('.compose_subject, .compose_body, .compose_server, .smtp_send_placeholder, .smtp_send_archive').on('focus', function(e) {
- $('.compose_to, .compose_cc, .compose_bcc').each(function() {
+ $('.compose_subject, .compose_body, .compose_server, .smtp_send_placeholder, .smtp_send_archive').on('focus', function (e) {
+ $('.compose_to, .compose_cc, .compose_bcc').each(function () {
bubbles_to_text(this);
});
});
- $('.compose_to, .compose_cc, .compose_bcc').on('focus', function(e) {
+ $('.compose_to, .compose_cc, .compose_bcc').on('focus', function (e) {
text_to_bubbles(this);
});
- $('.compose_container').on('click', function() {
+ $('.compose_container').on('click', function () {
$(this).find('input').focus();
});
- $(document).on('click', '.bubble_close', function(e) {
+ $(document).on('click', '.bubble_close', function (e) {
e.stopPropagation();
$(".bubble_dropdown-content").remove();
$(this).parent().remove();
@@ -222,7 +232,7 @@ function applyComposePageHandlers() {
var excludedEmail = null;
const excludeEmail = function () {
- var newRecipients = recipientsInput.val().split(',').filter(function(email) {
+ var newRecipients = recipientsInput.val().split(',').filter(function (email) {
if (email.includes(selectedEmail)) {
excludedEmail = email;
return false;
@@ -234,7 +244,7 @@ function applyComposePageHandlers() {
if (recipientsInput.val().includes(selectedEmail)) {
excludeEmail();
- $(document).on('change', '#compose_smtp_id', function() {
+ $(document).on('change', '#compose_smtp_id', function () {
if ($(this).val() !== selectedVal) {
if (!recipientsInput.val().includes(selectedEmail)) {
recipientsInput.val(recipientsInput.val() + ', ' + excludedEmail);
@@ -245,9 +255,10 @@ function applyComposePageHandlers() {
});
}
- $('.compose_to').on('keyup', function(e) { autocomplete_contact(e, '.compose_to', '#to_contacts'); });
- $('.compose_cc').on('keyup', function(e) { autocomplete_contact(e, '.compose_cc', '#cc_contacts'); });
- $('.compose_bcc').on('keyup', function(e) { autocomplete_contact(e, '.compose_bcc', '#bcc_contacts'); });
+
+ $('.compose_to').on('keyup', function (e) { autocomplete_contact(e, '.compose_to', '#to_contacts'); });
+ $('.compose_cc').on('keyup', function (e) { autocomplete_contact(e, '.compose_cc', '#cc_contacts'); });
+ $('.compose_bcc').on('keyup', function (e) { autocomplete_contact(e, '.compose_bcc', '#bcc_contacts'); });
$('.compose_to').focus();
if (window.pgpComposePageHandler) pgpComposePageHandler();
diff --git a/modules/smtp/modules.php b/modules/smtp/modules.php
index 5142ce3e3e..f79e2d5b50 100644
--- a/modules/smtp/modules.php
+++ b/modules/smtp/modules.php
@@ -113,6 +113,8 @@ public function process() {
}
}
+
+
/**
* @subpackage smtp/handler
*/
@@ -208,6 +210,7 @@ public function process() {
}
}
+
/**
* @subpackage smtp/handler
*/
@@ -317,6 +320,8 @@ 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;
+ $delivery_receipt = array_key_exists('compose_delivery_receipt', $this->request->post) ? $this->request->post['compose_delivery_receipt'] : 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);
@@ -333,7 +338,7 @@ public function process() {
if ($this->get('save_draft_to_imap') === false) {
$from = isset($profile) ? $profile['replyto'] : '';
$name = isset($profile) ? $profile['name'] : '';
- $mime = prepare_draft_mime($msg_attrs, $uploaded_files, $from, $name);
+ $mime = prepare_draft_mime($msg_attrs, $uploaded_files, $from, $name, $profile['id']);
$this->out('draft_mime', $mime);
return;
}
@@ -343,15 +348,20 @@ public function process() {
foreach($uploaded_files as $key => $file) {
$uploaded_files[$key] = $this->config->get('attachment_dir').DIRECTORY_SEPARATOR.$userpath.DIRECTORY_SEPARATOR.$file;
}
- $new_draft_id = save_imap_draft($msg_attrs, $draft_id, $this->session, $this, $this->cache, $uploaded_files, $profile);
+ $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, 'delivery_receipt' => $delivery_receipt, 'schedule' => $schedule), $draft_id, $this->session,
+ $this, $this->cache, $uploaded_files, $profile);
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);
}
elseif ($draft_notice) {
- Hm_Msgs::add('ERRUnable to save draft');
+ $msg = $schedule ? 'Something went wrong when scheduling draft' : 'Unable to save draft';
+ Hm_Msgs::add('ERR' . $msg);
}
return;
}
@@ -662,6 +672,9 @@ public function process() {
'draft_subject' => $form['compose_subject'],
'draft_smtp' => $smtp_id
);
+ $delivery_receipt = !empty($this->request->post['compose_delivery_receipt']);
+ $from_params = '';
+ $recipients_params = '';
/* parse attachments */
$uploaded_files = [];
@@ -706,7 +719,7 @@ public function process() {
}
/* build message */
- $mime = new Hm_MIME_Msg($to, $subject, $body, $from, $body_type, $cc, $bcc, $in_reply_to, $from_name, $reply_to);
+ $mime = new Hm_MIME_Msg($to, $subject, $body, $from, $body_type, $cc, $bcc, $in_reply_to, $from_name, $reply_to, $delivery_receipt);
/* add attachments */
$mime->add_attachments($uploaded_files);
@@ -875,6 +888,97 @@ protected function output() {
}
}
+/**
+ * Send scheduled messages
+ * @subpackage smtp/handler
+ */
+class Hm_Handler_send_scheduled_messages extends Hm_Handler_Module {
+ /**
+ * Send delayed messages
+ * This should use cron
+ */
+ public function process() {
+ if (!($this->module_is_supported('imap') || $this->module_is_supported('profiles'))) {
+ return;
+ }
+
+ $servers = Hm_IMAP_List::dump();
+ $scheduled_msg_count = 0;
+
+ foreach (array_keys($servers) as $server_id) {
+ $cache = Hm_IMAP_List::get_cache($this->cache, $server_id);
+ $imap = Hm_IMAP_List::connect($server_id, $cache);
+
+ if (imap_authed($imap)) {
+ $folder = 'Scheduled';
+ $ret = $imap->get_mailbox_page($folder, 'DATE', false, 'ALL');
+
+ foreach ($ret[1] as $msg) {
+ $msg_headers = $imap->get_message_headers($msg['uid']);
+
+ try {
+ if (!empty($msg_headers['X-Schedule'])) {
+ $scheduled_msg_count++;
+ } else {
+ continue;
+ }
+
+ if (send_scheduled_message($this, $imap, $msg, $server_id)) {
+ $scheduled_msg_count--;
+ }
+ } catch (Exception $e) {
+ Hm_Debug::add(sprintf('ERRCannot send message: %s', $msg_headers['subject']));
+ }
+ }
+ }
+ }
+
+ $this->out('scheduled_msg_count', $scheduled_msg_count);
+}}
+
+/**
+ * Changes the schedule of the message
+ * @subpackage smtp/handler
+ */
+class Hm_Handler_re_schedule_message_sending extends Hm_Handler_Module {
+ public function process() {
+ if (!($this->module_is_supported('imap') || $this->module_is_supported('profiles'))) {
+ return;
+ }
+ list($success, $form) = $this->process_form(array('schedule_date', 'scheduled_msg_ids'));
+ if (!$success) {
+ return;
+ }
+ $scheduled_msg_count = 0;
+ $new_schedule_date = $form['schedule_date'];
+ if ($form['schedule_date'] != 'now') {
+ $new_schedule_date = get_scheduled_date($form['schedule_date']);
+ }
+ $ids = explode(',', $form['scheduled_msg_ids']);
+ foreach ($ids as $msg_part) {
+ list($imap_server_id, $msg_id, $folder) = explode('_', $msg_part);
+ $cache = Hm_IMAP_List::get_cache($this->cache, $imap_server_id);
+ $imap = Hm_IMAP_List::connect($imap_server_id, $cache);
+ if (imap_authed($imap)) {
+ $folder = hex2bin($folder);
+ if (reschedule_message_sending($this, $imap, $msg_id, $folder, $new_schedule_date, $imap_server_id)) {
+ $scheduled_msg_count++;
+ }
+ }
+ }
+ $this->out('scheduled_msg_count', $scheduled_msg_count);
+ if ($scheduled_msg_count == count($ids)) {
+ $msg = 'Operation successful';
+ } elseif ($scheduled_msg_count > 0) {
+ $msg = 'Some messages have been scheduled for sending';
+ } else {
+ $msg = 'ERRFailed to schedule sending for messages';
+ }
+ Hm_Msgs::add($msg);
+ $this->save_hm_msgs();
+ }
+}
+
/**
* @subpackage keyboard_shortcuts/output
*/
@@ -1226,11 +1330,15 @@ protected function output() {
}
}
}
-
$res .= ''.
smtp_server_dropdown($this->module_output(), $this, $recip, $selected_id).
- '
'.$this->trans('Send').' ';
-
+ '
+ '.$this->trans('Send').'
+
+ Toggle Dropdown
+ '.
+ schedule_dropdown($this).
+ '
';
if ($this->get('list_path') && ($reply_type == 'reply' || $reply_type == 'reply_all')) {
$res .= '
';
}
@@ -1527,6 +1635,20 @@ protected function output() {
}
}
+/**
+ * Add scheduled send to the message list controls
+ * @subpackage imap/output
+ */
+class Hm_Output_scheduled_send_msg_control extends Hm_Output_Module {
+ protected function output() {
+ $parts = explode('_', $this->get('list_path'));
+ if ($parts[0] == 'imap' && hex2bin($parts[2]) == 'Scheduled') {
+ $res = schedule_dropdown($this, true);
+ $this->concat('msg_controls_extra', $res);
+ }
+ }
+}
+
/**
* @subpackage smtp/functions
*/
@@ -1853,10 +1975,8 @@ function get_uploaded_files_from_array($uploaded_files) {
}
}
-function prepare_draft_mime($atts, $uploaded_files, $from = false, $name = '') {
- if (! empty($uploaded_files) && ! is_array($uploaded_files[0])) {
- $uploaded_files = get_uploaded_files_from_array($uploaded_files);
- }
+function prepare_draft_mime($atts, $uploaded_files, $from = false, $name = '', $profile_id = null) {
+ $uploaded_files = get_uploaded_files_from_array($uploaded_files);
$mime = new Hm_MIME_Msg(
$atts['draft_to'],
$atts['draft_subject'],
@@ -1867,7 +1987,10 @@ function prepare_draft_mime($atts, $uploaded_files, $from = false, $name = '') {
$atts['draft_bcc'],
'',
$name,
- $atts['draft_in_reply_to']
+ $atts['draft_in_reply_to'],
+ $atts['delivery_receipt'],
+ $atts['schedule'],
+ $profile_id
);
$mime->add_attachments($uploaded_files);
@@ -1906,28 +2029,40 @@ 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;
}
- $mailbox = Hm_IMAP_List::get_connected_mailbox($imap_profile['id'], $mod_cache);
- if (! $mailbox || ! $mailbox->authed()) {
- return -1;
+ $cache = Hm_IMAP_List::get_cache($mod_cache, $imap_profile['id']);
+ $imap = Hm_IMAP_List::connect($imap_profile['id'], $cache);
+
+ if (!empty($atts['schedule'])) {
+ $folder ='Scheduled';
+ if (!count($imap->get_mailbox_status($folder))) {
+ $imap->create_mailbox($folder);
+ }
+ $atts['schedule'] = get_scheduled_date($atts['schedule']);
+ } else {
+ $folder = $specials['draft'];
}
+ $imap->select_mailbox($folder);
- $mime = prepare_draft_mime($atts, $uploaded_files, $from, $name);
+ $mime = prepare_draft_mime($atts, $uploaded_files, $from, $name, $profile['id']);
$res = $mime->process_attachments();
-
+
$msg = str_replace("\r\n", "\n", $mime->get_mime_msg());
$msg = str_replace("\n", "\r\n", $msg);
$msg = rtrim($msg)."\r\n";
- if (! $mailbox->store_message($specials['draft'], $msg, false, true)) {
- Hm_Msgs::add('ERRAn error occurred saving the draft message');
- return -1;
+ if ($imap->append_start($folder, mb_strlen($msg), false, true)) {
+ $imap->append_feed($msg."\r\n");
+ if (!$imap->append_end()) {
+ Hm_Msgs::add('ERRAn error occurred saving the draft message');
+ return -1;
+ }
}
- $messages = $mailbox->get_messages($specials['draft'], 'ARRIVAL', true, 'DRAFT', 0, 10);
+ $mailbox_page = $imap->get_mailbox_page($folder, 'ARRIVAL', true, 'DRAFT', 0, 10);
// Remove old version from the mailbox
if ($id) {
@@ -2208,4 +2343,4 @@ function recip_count_check($headers, $omod) {
if ($recip_count > MAX_RECIPIENT_WARNING) {
Hm_Msgs::add('ERRMessage contains more than the maximum number of recipients, proceed with caution');
}
-}}
+}}
\ No newline at end of file
diff --git a/modules/smtp/setup.php b/modules/smtp/setup.php
index 916bf9e613..c16fddecb5 100644
--- a/modules/smtp/setup.php
+++ b/modules/smtp/setup.php
@@ -21,6 +21,7 @@
add_handler('compose', 'load_smtp_is_imap_forward_as_attachment', true, 'smtp', 'load_user_data', 'after');
add_handler('compose', 'load_smtp_is_imap_forward', true, 'smtp', 'load_smtp_is_imap_forward_as_attachment', 'after');
+
add_handler('functional_api', 'default_smtp_server', true, 'smtp');
add_handler('profiles', 'load_smtp_servers_from_config', true, 'smtp', 'load_user_data', 'after');
@@ -102,6 +103,20 @@
add_handler('settings', 'process_enable_compose_delivery_receipt_setting', true, 'core', 'save_user_settings', 'before');
add_output('settings', 'enable_compose_delivery_receipt_setting', true, 'core', 'start_general_settings', 'after');
+/* send delayed emails */
+setup_base_ajax_page('ajax_send_scheduled_messages', 'core');
+add_handler('ajax_send_scheduled_messages', 'load_imap_servers_from_config', true, 'imap', 'load_user_data', 'after');
+add_handler('ajax_send_scheduled_messages', 'load_smtp_servers_from_config', true, 'smtp', 'load_user_data', 'after');
+add_handler('ajax_send_scheduled_messages', 'compose_profile_data', true, 'profiles');
+add_handler('ajax_send_scheduled_messages', 'send_scheduled_messages', true, 'smtp');
+
+setup_base_ajax_page('ajax_re_schedule_message_sending', 'core');
+add_handler('ajax_re_schedule_message_sending', 'load_imap_servers_from_config', true, 'imap', 'load_user_data', 'after');
+add_handler('ajax_re_schedule_message_sending', 'load_smtp_servers_from_config', true, 'smtp', 'load_user_data', 'after');
+add_handler('ajax_re_schedule_message_sending', 'compose_profile_data', true, 'profiles');
+add_handler('ajax_re_schedule_message_sending', 're_schedule_message_sending', true, 'smtp');
+
+add_output('message_list', 'scheduled_send_msg_control', true, 'smtp', 'imap_custom_controls', 'after');
return array(
'allowed_pages' => array(
@@ -112,7 +127,9 @@
'ajax_profiles_status',
'ajax_attachment_reminder_check',
'ajax_get_test_chunk',
- 'ajax_upload_chunk'
+ 'ajax_upload_chunk',
+ 'ajax_send_scheduled_messages',
+ 'ajax_re_schedule_message_sending'
),
'allowed_get' => array(
'imap_draft' => FILTER_VALIDATE_INT,
@@ -144,9 +161,13 @@
'msg_sent_and_archived' => array(FILTER_VALIDATE_BOOLEAN, false),
'sent_msg_id' => array(FILTER_VALIDATE_BOOLEAN, false),
'enable_attachment_reminder' => array(FILTER_VALIDATE_BOOLEAN, false),
+ 'scheduled_msg_count' => array(FILTER_VALIDATE_INT, false),
),
'allowed_post' => array(
'post_archive' => FILTER_VALIDATE_INT,
+ 'send_tomorrow_morning' => FILTER_DEFAULT,
+ 'send_today_afternoon' => FILTER_DEFAULT,
+ 'schedule_sending' => FILTER_DEFAULT,
'attachment_id' => FILTER_DEFAULT,
'smtp_compose_type' => FILTER_VALIDATE_INT,
'new_smtp_name' => FILTER_DEFAULT,
@@ -185,6 +206,9 @@
'uploaded_files' => FILTER_DEFAULT,
'send_uploaded_files' => FILTER_DEFAULT,
'next_email_post' => FILTER_DEFAULT,
- 'enable_attachment_reminder' => FILTER_VALIDATE_INT
+ 'enable_attachment_reminder' => FILTER_VALIDATE_INT,
+ 'schedule' => FILTER_DEFAULT,
+ 'schedule_date' => FILTER_DEFAULT,
+ 'scheduled_msg_ids' => FILTER_DEFAULT,
)
);
diff --git a/modules/smtp/site.js b/modules/smtp/site.js
index 30a6bce694..2c60c8b688 100644
--- a/modules/smtp/site.js
+++ b/modules/smtp/site.js
@@ -28,7 +28,7 @@ var smtp_test_action = function(event) {
false,
{'smtp_connect': 1}
);
-};
+};
var smtp_delete_action = function(event) {
if (!hm_delete_prompt()) {
@@ -69,7 +69,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) {
var no_icon = true;
if (notice) {
no_icon = false;
@@ -82,6 +82,7 @@ var save_compose_state = function(no_files, notice) {
var cc = $('.compose_cc').val();
var bcc = $('.compose_bcc').val();
var inreplyto = $('.compose_in_reply_to').val();
+ var delivery_receipt = $('#compose_delivery_receipt').prop('checked');
var draft_id = $('.compose_draft_id').val();
if (globals.draft_state == body+subject+to+smtp+cc+bcc+uploaded_files) {
@@ -105,6 +106,8 @@ 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': 'compose_delivery_receipt', 'value': delivery_receipt},
{'name': 'uploaded_files', 'value': uploaded_files}],
function(res) {
if (res.draft_id) {
@@ -113,6 +116,15 @@ var save_compose_state = function(no_files, notice) {
if (res.draft_subject) {
$('.draft_list .draft_'+draft_id+' a').text(res.draft_subject);
}
+
+ if (schedule) {
+ $(".compose_form")[0].reset();
+ return;
+ }
+
+ if (callback) {
+ callback(res);
+ }
},
[],
no_icon
@@ -138,7 +150,7 @@ function smtpServersPageHandler() {
}
}
-var reset_smtp_form = function() {
+var reset_smtp_form = function(save = true) {
$('.compose_body').val('');
$('.compose_subject').val('');
$('.compose_to').val('');
@@ -146,7 +158,10 @@ var reset_smtp_form = function() {
$('.compose_bcc').val('');
$('.ke-content', $('iframe').contents()).html('');
$('.uploaded_files').html('');
- save_compose_state(true);
+ $('#compose_delivery_receipt').prop('checked', false);
+ if (save) {
+ save_compose_state(true);
+ }
};
var replace_cursor_positon = function (txtElement) {
@@ -382,4 +397,4 @@ function smtpSettingsPageHandler() {
[]
);
});
-}
+}
\ No newline at end of file