Skip to content

Commit f02b5be

Browse files
committed
feat(spam): enhance spam reporting with delayed logging and modal interface
1 parent e4f54e0 commit f02b5be

File tree

2 files changed

+230
-90
lines changed

2 files changed

+230
-90
lines changed

modules/imap/handler_modules.php

Lines changed: 91 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88

99
if (!defined('DEBUG_MODE')) { die(); }
1010

11+
// Add helper function for delayed logging
12+
function delayed_debug_log($message, $data = null, $delay = 1) {
13+
if ($data) {
14+
Hm_Debug::add($message . ': ' . json_encode($data));
15+
} else {
16+
Hm_Debug::add($message);
17+
}
18+
sleep($delay);
19+
}
1120

1221
/**
1322
* Check for attachments when forwarding a message
@@ -2089,78 +2098,100 @@ class Hm_Handler_imap_report_spam extends Hm_Handler_Module {
20892098
* Use IMAP to move the selected message to the junk folder
20902099
*/
20912100
public function process() {
2092-
Hm_Debug::add('Report Spam handler starting');
2093-
list($success, $form) = $this->process_form(array('imap_msg_uid', 'imap_server_id', 'folder'));
2094-
Hm_Debug::add('Form processing result:', array('success' => $success, 'form' => $form));
2095-
2096-
if (!$success) {
2097-
Hm_Debug::add('Form processing failed');
2098-
return;
2099-
}
2101+
try {
2102+
delayed_debug_log('Report Spam handler starting');
2103+
// Remove spam_reason from required fields
2104+
list($success, $form) = $this->process_form(array('imap_msg_uid', 'imap_server_id', 'folder'));
2105+
delayed_debug_log('Form processing result:', array('success' => $success, 'form' => $form));
21002106

2101-
$junk_folder = false;
2102-
$form_folder = hex2bin($form['folder']);
2103-
$errors = 0;
2104-
$status = null;
2107+
if (!$success) {
2108+
delayed_debug_log('Form processing failed - missing required fields');
2109+
Hm_Msgs::add('Failed to process spam report: Missing required fields', 'error');
2110+
$this->out('imap_report_spam_error', true);
2111+
return;
2112+
}
21052113

2106-
$specials = get_special_folders($this, $form['imap_server_id']);
2107-
Hm_Debug::add('Special folders:', $specials);
2108-
2109-
if (array_key_exists('junk', $specials) && $specials['junk']) {
2110-
$junk_folder = $specials['junk'];
2111-
Hm_Debug::add('Found junk folder:', $junk_folder);
2112-
}
2114+
if (!isset($form['imap_msg_uid']) || !isset($form['imap_server_id']) || !isset($form['folder'])) {
2115+
delayed_debug_log('Missing required form fields:', $form);
2116+
Hm_Msgs::add('Failed to process spam report: Invalid request data', 'error');
2117+
$this->out('imap_report_spam_error', true);
2118+
return;
2119+
}
21132120

2114-
$mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
2115-
Hm_Debug::add('Mailbox connection:', array(
2116-
'connected' => ($mailbox !== false),
2117-
'authed' => ($mailbox && $mailbox->authed()),
2118-
'is_imap' => ($mailbox && $mailbox->is_imap())
2119-
));
2121+
$junk_folder = false;
2122+
$form_folder = hex2bin($form['folder']);
2123+
$errors = 0;
2124+
$status = null;
2125+
// Get spam_reason from form if it exists, otherwise use default
2126+
$spam_reason = isset($form['spam_reason']) && !empty($form['spam_reason']) ?
2127+
$form['spam_reason'] : 'No reason provided';
2128+
2129+
// Log the spam report
2130+
$log_entry = sprintf(
2131+
"Spam Report - Time: %s, Server: %s, Folder: %s, UID: %s, Reason: %s",
2132+
date('Y-m-d H:i:s'),
2133+
$form['imap_server_id'],
2134+
$form_folder,
2135+
$form['imap_msg_uid'],
2136+
$spam_reason
2137+
);
2138+
delayed_debug_log('Spam report log:', $log_entry);
21202139

2121-
if ($mailbox && !$mailbox->is_imap() && empty($junk_folder)) {
2122-
Hm_Debug::add('Using EWS JUNK action');
2123-
// EWS supports moving to junk folder directly
2124-
$status = $mailbox->message_action($form_folder, 'JUNK', array($form['imap_msg_uid']))['status'];
2125-
Hm_Debug::add('EWS JUNK action result:', $status);
2126-
} else {
2127-
if (!$junk_folder) {
2128-
Hm_Debug::add('No junk folder configured');
2140+
$specials = get_special_folders($this, $form['imap_server_id']);
2141+
delayed_debug_log('Special folders:', $specials);
2142+
2143+
if (array_key_exists('junk', $specials) && $specials['junk']) {
2144+
$junk_folder = $specials['junk'];
2145+
delayed_debug_log('Found junk folder:', $junk_folder);
2146+
} else {
2147+
delayed_debug_log('No junk folder configured');
21292148
Hm_Msgs::add('No junk folder configured for this IMAP server', 'warning');
21302149
$errors++;
21312150
}
21322151

2133-
if (!$errors && $mailbox && $mailbox->authed()) {
2134-
$junk_exists = count($mailbox->get_folder_status($junk_folder));
2135-
Hm_Debug::add('Junk folder status:', array(
2136-
'folder' => $junk_folder,
2137-
'exists' => $junk_exists
2152+
$mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $this->cache);
2153+
delayed_debug_log('Mailbox connection:', array(
2154+
'connected' => ($mailbox !== false),
2155+
'authed' => ($mailbox && $mailbox->authed()),
2156+
'is_imap' => ($mailbox && $mailbox->is_imap())
2157+
));
2158+
2159+
if (!$mailbox) {
2160+
delayed_debug_log('Failed to connect to mailbox');
2161+
Hm_Msgs::add('Failed to connect to mailbox', 'error');
2162+
$errors++;
2163+
} elseif (!$mailbox->authed()) {
2164+
delayed_debug_log('Not authenticated to mailbox');
2165+
Hm_Msgs::add('Not authenticated to mailbox', 'error');
2166+
$errors++;
2167+
}
2168+
2169+
if (!$errors) {
2170+
delayed_debug_log('Attempting to move message to junk folder', array(
2171+
'from_folder' => $form_folder,
2172+
'to_folder' => $junk_folder,
2173+
'uid' => $form['imap_msg_uid']
21382174
));
2139-
2140-
if (!$junk_exists) {
2141-
Hm_Debug::add('Junk folder does not exist');
2142-
Hm_Msgs::add('Configured junk folder for this IMAP server does not exist', 'warning');
2143-
$errors++;
2144-
}
2175+
$result = $mailbox->message_action($form_folder, 'MOVE', array($form['imap_msg_uid']), $junk_folder);
2176+
$status = $result['status'];
2177+
delayed_debug_log('Move action result:', array('status' => $status, 'result' => $result));
2178+
}
21452179

2146-
/* try to move the message */
2147-
if (!$errors) {
2148-
Hm_Debug::add('Attempting to move message to junk folder');
2149-
$status = $mailbox->message_action($form_folder, 'MOVE', array($form['imap_msg_uid']), $junk_folder)['status'];
2150-
Hm_Debug::add('Move action result:', $status);
2151-
}
2180+
if ($status) {
2181+
delayed_debug_log('Message successfully reported as spam');
2182+
Hm_Msgs::add("Message reported as spam and moved to junk folder");
2183+
} else {
2184+
delayed_debug_log('Failed to report message as spam');
2185+
Hm_Msgs::add('An error occurred reporting the message as spam', 'danger');
21522186
}
2153-
}
21542187

2155-
if ($status) {
2156-
Hm_Debug::add('Message successfully reported as spam');
2157-
Hm_Msgs::add("Message reported as spam");
2158-
} else {
2159-
Hm_Debug::add('Failed to report message as spam');
2160-
Hm_Msgs::add('An error occurred reporting the message as spam', 'danger');
2188+
$this->out('imap_report_spam_error', !$status);
2189+
$this->save_hm_msgs();
2190+
} catch (Exception $e) {
2191+
delayed_debug_log('Exception in spam report handler: ' . $e->getMessage());
2192+
Hm_Msgs::add('An unexpected error occurred while reporting spam', 'error');
2193+
$this->out('imap_report_spam_error', true);
2194+
$this->save_hm_msgs();
21612195
}
2162-
2163-
$this->out('imap_report_spam_error', !$status);
2164-
$this->save_hm_msgs();
21652196
}
21662197
}

modules/imap/site.js

Lines changed: 139 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
'use strict';
22

3+
// Add helper function for delayed logging
4+
function delayedLog(message, data = null, delay = 1000) {
5+
setTimeout(() => {
6+
if (data) {
7+
console.log(message, data);
8+
} else {
9+
console.log(message);
10+
}
11+
}, delay);
12+
}
13+
14+
// Add helper function for displaying messages
15+
function showMessage(message, type = 'info') {
16+
if (typeof Hm_Msgs !== 'undefined') {
17+
Hm_Msgs.add(message, type);
18+
} else if (typeof hm_msgs !== 'undefined' && typeof hm_msgs.add === 'function') {
19+
hm_msgs.add(message, type);
20+
} else {
21+
console.log(`[${type.toUpperCase()}] ${message}`);
22+
}
23+
}
24+
325
var imap_delete_action = function(event) {
426
if (!hm_delete_prompt()) {
527
return false;
@@ -1265,12 +1287,86 @@ $(function() {
12651287
}
12661288
setTimeout(prefetch_imap_folders, 2);
12671289

1268-
$('#report_spam_message').on("click", function(e) { return imap_report_spam_message(); });
1290+
// Add spam report modal to the page
1291+
if (!$('#spamReportModal').length) {
1292+
$('body').append(`
1293+
<div class="modal fade" id="spamReportModal" tabindex="-1" aria-labelledby="spamReportModalLabel" aria-hidden="true">
1294+
<div class="modal-dialog">
1295+
<div class="modal-content">
1296+
<div class="modal-header">
1297+
<h5 class="modal-title" id="spamReportModalLabel">Report Spam</h5>
1298+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
1299+
</div>
1300+
<div class="modal-body">
1301+
<div class="mb-3">
1302+
<label for="spamReportReason" class="form-label">Reason for reporting as spam:</label>
1303+
<textarea class="form-control" id="spamReportReason" rows="3">This message appears to be unsolicited commercial email or contains suspicious content.</textarea>
1304+
</div>
1305+
</div>
1306+
<div class="modal-footer">
1307+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
1308+
<button type="button" class="btn btn-danger" id="confirmSpamReport">Report as Spam</button>
1309+
</div>
1310+
</div>
1311+
</div>
1312+
</div>
1313+
`);
1314+
}
1315+
12691316
$(document).on('click', '.msg_report_spam', function(e) {
12701317
e.preventDefault();
1271-
var uid = getMessageUidParam();
1272-
var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
1273-
return imap_report_spam_message(false, uid, detail);
1318+
var uid, detail;
1319+
1320+
// Check if we're in message list view
1321+
var selected = $('input[type=checkbox]:checked', $('.message_table')).closest('tr');
1322+
if (selected.length > 0) {
1323+
// We're in message list view
1324+
uid = selected.data('uid');
1325+
detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
1326+
} else {
1327+
// We're in message view
1328+
uid = getMessageUidParam();
1329+
detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
1330+
}
1331+
1332+
if (!uid) {
1333+
delayedLog('Missing UID', null, 0);
1334+
showMessage('Could not determine message ID', 'error');
1335+
return false;
1336+
}
1337+
1338+
// Store the message details for the modal
1339+
$('#spamReportModal').data('uid', uid).data('detail', detail);
1340+
1341+
// Show the modal
1342+
var modal = new bootstrap.Modal(document.getElementById('spamReportModal'));
1343+
modal.show();
1344+
1345+
return false;
1346+
});
1347+
1348+
// Handle the confirm button click
1349+
$(document).on('click', '#confirmSpamReport', function() {
1350+
var modal = $('#spamReportModal');
1351+
var uid = modal.data('uid');
1352+
var detail = modal.data('detail');
1353+
var reason = $('#spamReportReason').val().trim();
1354+
1355+
if (!reason) {
1356+
showMessage('Please provide a reason for reporting this message as spam', 'warning');
1357+
return;
1358+
}
1359+
1360+
if (!uid) {
1361+
showMessage('Could not determine message ID', 'error');
1362+
return;
1363+
}
1364+
1365+
// Hide the modal
1366+
bootstrap.Modal.getInstance(document.getElementById('spamReportModal')).hide();
1367+
1368+
// Call the report spam function with the reason
1369+
return imap_report_spam_message(false, uid, detail, reason);
12741370
});
12751371
});
12761372

@@ -1313,44 +1409,49 @@ var imap_archive_message = function(state, supplied_uid, supplied_detail) {
13131409
return false;
13141410
};
13151411

1316-
var imap_report_spam_message = function(state, supplied_uid, supplied_detail) {
1317-
console.log('Report Spam clicked - Starting process');
1318-
var uid = getMessageUidParam();
1319-
var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
1320-
console.log('Message details:', {uid: uid, detail: detail});
1412+
var imap_report_spam_message = function(state, supplied_uid, supplied_detail, reason) {
1413+
delayedLog('Report Spam clicked - Starting process');
1414+
var uid = supplied_uid || getMessageUidParam();
1415+
var detail = supplied_detail || Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
1416+
delayedLog('Message details:', {uid: uid, detail: detail, reason: reason});
13211417

1322-
if (supplied_uid) {
1323-
uid = supplied_uid;
1324-
}
1325-
if (supplied_detail) {
1326-
detail = supplied_detail;
1418+
if (!uid) {
1419+
delayedLog('Missing UID', null, 0);
1420+
showMessage('Could not determine message ID', 'error');
1421+
return false;
13271422
}
1423+
13281424
if (detail && uid) {
1329-
console.log('Making AJAX request to report spam with params:', {
1330-
hook: 'ajax_imap_report_spam',
1331-
uid: uid,
1332-
server_id: detail.server_id,
1333-
folder: detail.folder
1334-
});
1335-
Hm_Ajax.request(
1336-
[{'name': 'hm_ajax_hook', 'value': 'ajax_imap_report_spam'},
1425+
// Construct form data
1426+
var form_data = [
1427+
{'name': 'hm_ajax_hook', 'value': 'ajax_imap_report_spam'},
13371428
{'name': 'imap_msg_uid', 'value': uid},
13381429
{'name': 'imap_server_id', 'value': detail.server_id},
1339-
{'name': 'folder', 'value': detail.folder}],
1430+
{'name': 'folder', 'value': detail.folder}
1431+
];
1432+
1433+
// Always include spam_reason, even if empty
1434+
form_data.push({'name': 'spam_reason', 'value': reason || 'No reason provided'});
1435+
1436+
delayedLog('Making AJAX request to report spam with form data:', form_data);
1437+
1438+
Hm_Ajax.request(
1439+
form_data,
13401440
function(res) {
1341-
console.log('Report spam AJAX response:', res);
1441+
delayedLog('Report spam AJAX response:', res);
13421442
if (!res.imap_report_spam_error) {
1443+
showMessage('Message reported as spam and moved to junk folder', 'success');
13431444
if (Hm_Utils.get_from_global('msg_uid', false)) {
1344-
console.log('Message UID in global, returning');
1445+
delayedLog('Message UID in global, returning');
13451446
return;
13461447
}
13471448
var nlink = $('.nlink');
13481449
if (nlink.length && Hm_Utils.get_from_global('auto_advance_email_enabled')) {
1349-
console.log('Auto-advance enabled, redirecting to next message');
1450+
delayedLog('Auto-advance enabled, redirecting to next message');
13501451
Hm_Utils.redirect(nlink.attr('href'));
13511452
}
13521453
else {
1353-
console.log('Redirecting to message list');
1454+
delayedLog('Redirecting to message list');
13541455
if (!hm_list_parent()) {
13551456
Hm_Utils.redirect("?page=message_list&list_path="+getListPathParam());
13561457
}
@@ -1359,12 +1460,20 @@ var imap_report_spam_message = function(state, supplied_uid, supplied_detail) {
13591460
}
13601461
}
13611462
} else {
1362-
console.error('Error in report spam response:', res.imap_report_spam_error);
1463+
delayedLog('Error in report spam response:', res.imap_report_spam_error);
1464+
var errorMsg = 'Failed to report message as spam';
1465+
if (res.router_user_msgs && res.router_user_msgs.text) {
1466+
errorMsg += ': ' + res.router_user_msgs.text;
1467+
}
1468+
showMessage(errorMsg, 'error');
13631469
}
1364-
}
1470+
},
1471+
true, // Show loading icon
1472+
true // Handle errors
13651473
);
13661474
} else {
1367-
console.error('Missing required details:', {detail: detail, uid: uid});
1475+
delayedLog('Missing required details:', {detail: detail, uid: uid}, 0);
1476+
showMessage('Could not process spam report: Missing required details', 'error');
13681477
}
13691478
return false;
13701479
};

0 commit comments

Comments
 (0)