feat: implement server-side IMAP LIST and SEARCH filtering in Rust
Add server-side folder filtering using IMAP LIST patterns and enhance message filtering to use IMAP SEARCH with keyword filters when available. Key improvements: - Add list_filtered_mailboxes() method using IMAP LIST with patterns - Use server-side filtering instead of client-side folder filtering - Enhance message search to use IMAP SEARCH for subject/sender keywords - Add has_keyword_filters() method to MessageFilter - Reduce network traffic by leveraging IMAP server capabilities - Remove dependency on client-side filter_folders function This achieves full feature parity with the updated Go implementation and ensures both versions use IMAP standards optimally. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
84faf501f1
commit
ee236db3c1
3 changed files with 140 additions and 15 deletions
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
use crate::config::{Config, MailSource, CommandLineArgs};
|
||||
use crate::couch::CouchClient;
|
||||
use crate::filters::{filter_folders, get_filter_summary, validate_folder_patterns};
|
||||
use crate::filters::{get_filter_summary, validate_folder_patterns};
|
||||
use crate::imap::{ImapClient, should_process_message};
|
||||
use crate::schemas::{SyncMetadata, generate_database_name};
|
||||
use anyhow::{anyhow, Result};
|
||||
|
|
@ -125,19 +125,27 @@ impl SyncCoordinator {
|
|||
// Connect to IMAP server
|
||||
let mut imap_client = ImapClient::connect(source.clone()).await?;
|
||||
|
||||
// Get list of available mailboxes
|
||||
let all_mailboxes = imap_client.list_mailboxes().await?;
|
||||
info!("Found {} total mailboxes", all_mailboxes.len());
|
||||
// Use IMAP LIST with patterns for server-side filtering
|
||||
let filtered_mailboxes = imap_client.list_filtered_mailboxes(&source.folder_filter).await?;
|
||||
info!("Found {} matching mailboxes after server-side filtering", filtered_mailboxes.len());
|
||||
|
||||
// Apply folder filtering
|
||||
let filtered_mailboxes = filter_folders(&all_mailboxes, &source.folder_filter);
|
||||
let filter_summary = get_filter_summary(&all_mailboxes, &filtered_mailboxes, &source.folder_filter);
|
||||
info!("{}", filter_summary);
|
||||
// For validation and summary, we still need the full list
|
||||
let all_mailboxes = if !source.folder_filter.include.is_empty() || !source.folder_filter.exclude.is_empty() {
|
||||
// Only fetch all mailboxes if we have filters (for logging/validation)
|
||||
imap_client.list_mailboxes().await.unwrap_or_else(|_| Vec::new())
|
||||
} else {
|
||||
filtered_mailboxes.clone()
|
||||
};
|
||||
|
||||
// Validate folder patterns and show warnings
|
||||
let warnings = validate_folder_patterns(&source.folder_filter, &all_mailboxes);
|
||||
for warning in warnings {
|
||||
warn!("{}", warning);
|
||||
if !all_mailboxes.is_empty() {
|
||||
let filter_summary = get_filter_summary(&all_mailboxes, &filtered_mailboxes, &source.folder_filter);
|
||||
info!("{}", filter_summary);
|
||||
|
||||
// Validate folder patterns and show warnings
|
||||
let warnings = validate_folder_patterns(&source.folder_filter, &all_mailboxes);
|
||||
for warning in warnings {
|
||||
warn!("{}", warning);
|
||||
}
|
||||
}
|
||||
|
||||
// Sync each filtered mailbox
|
||||
|
|
@ -222,9 +230,32 @@ impl SyncCoordinator {
|
|||
}
|
||||
};
|
||||
|
||||
// Search for messages
|
||||
let message_uids = imap_client.search_messages(since_date.as_ref()).await?;
|
||||
info!(" Found {} messages to process", message_uids.len());
|
||||
// Search for messages using server-side IMAP SEARCH with keyword filtering when possible
|
||||
let message_uids = if source.message_filter.has_keyword_filters() {
|
||||
// Use advanced IMAP SEARCH with keyword filtering
|
||||
let subject_keywords = if source.message_filter.subject_keywords.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(source.message_filter.subject_keywords.as_slice())
|
||||
};
|
||||
let from_keywords = if source.message_filter.sender_keywords.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(source.message_filter.sender_keywords.as_slice())
|
||||
};
|
||||
|
||||
info!(" Using IMAP SEARCH with keyword filters");
|
||||
imap_client.search_messages_advanced(
|
||||
since_date.as_ref(),
|
||||
None, // before_date
|
||||
subject_keywords,
|
||||
from_keywords,
|
||||
).await?
|
||||
} else {
|
||||
// Use simple date-based search
|
||||
imap_client.search_messages(since_date.as_ref()).await?
|
||||
};
|
||||
info!(" Found {} messages matching search criteria", message_uids.len());
|
||||
|
||||
// Handle sync mode - check for deleted messages
|
||||
let mut messages_deleted = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue