@@ -250,6 +250,16 @@ impl SchedulerState {
250250 }
251251 }
252252
253+ pub ( crate ) async fn clear_all_relay_storage ( & self ) -> Result < ( ) > {
254+ let inner = self . inner . read ( ) . await ;
255+ if let InnerSchedulerState :: Started ( ref scheduler) = * inner {
256+ scheduler. clear_all_relay_storage ( ) ;
257+ Ok ( ( ) )
258+ } else {
259+ bail ! ( "IO is not started" ) ;
260+ }
261+ }
262+
253263 pub ( crate ) async fn interrupt_smtp ( & self ) {
254264 let inner = self . inner . read ( ) . await ;
255265 if let InnerSchedulerState :: Started ( ref scheduler) = * inner {
@@ -348,6 +358,7 @@ async fn inbox_loop(
348358 let ImapConnectionHandlers {
349359 mut connection,
350360 stop_token,
361+ clear_storage_request_receiver,
351362 } = inbox_handlers;
352363
353364 let transport_id = connection. transport_id ( ) ;
@@ -386,7 +397,14 @@ async fn inbox_loop(
386397 }
387398 } ;
388399
389- match inbox_fetch_idle ( & ctx, & mut connection, session) . await {
400+ match inbox_fetch_idle (
401+ & ctx,
402+ & mut connection,
403+ session,
404+ & clear_storage_request_receiver,
405+ )
406+ . await
407+ {
390408 Err ( err) => warn ! (
391409 ctx,
392410 "Transport {transport_id}: Failed inbox fetch_idle: {err:#}."
@@ -407,11 +425,29 @@ async fn inbox_loop(
407425 . await ;
408426}
409427
410- async fn inbox_fetch_idle ( ctx : & Context , imap : & mut Imap , mut session : Session ) -> Result < Session > {
428+ async fn inbox_fetch_idle (
429+ ctx : & Context ,
430+ imap : & mut Imap ,
431+ mut session : Session ,
432+ clear_storage_request_receiver : & Receiver < ( ) > ,
433+ ) -> Result < Session > {
411434 let transport_id = session. transport_id ( ) ;
412435
436+ // Clear IMAP storage on request.
437+ //
438+ // Only doing this for chatmail relays to avoid
439+ // accidentally deleting all emails in a shared mailbox.
440+ let should_clear_imap_storage =
441+ clear_storage_request_receiver. try_recv ( ) . is_ok ( ) && session. is_chatmail ( ) ;
442+ if should_clear_imap_storage {
443+ info ! ( ctx, "Transport {transport_id}: Clearing IMAP storage." ) ;
444+ session. delete_all_messages ( ctx, & imap. folder ) . await ?;
445+ }
446+
413447 // Update quota no more than once a minute.
414- if ctx. quota_needs_update ( session. transport_id ( ) , 60 ) . await
448+ //
449+ // Always update if we just cleared IMAP storage.
450+ if ( ctx. quota_needs_update ( session. transport_id ( ) , 60 ) . await || should_clear_imap_storage)
415451 && let Err ( err) = ctx. update_recent_quota ( & mut session, & imap. folder ) . await
416452 {
417453 warn ! (
@@ -737,6 +773,12 @@ impl Scheduler {
737773 }
738774 }
739775
776+ fn clear_all_relay_storage ( & self ) {
777+ for b in & self . inboxes {
778+ b. conn_state . clear_relay_storage ( ) ;
779+ }
780+ }
781+
740782 fn interrupt_smtp ( & self ) {
741783 self . smtp . interrupt ( ) ;
742784 }
@@ -870,6 +912,13 @@ struct SmtpConnectionHandlers {
870912#[ derive( Debug ) ]
871913pub ( crate ) struct ImapConnectionState {
872914 state : ConnectionState ,
915+
916+ /// Channel to request clearing the folder.
917+ ///
918+ /// IMAP loop receiving this should clear the folder
919+ /// on the next iteration if IMAP server is a chatmail relay
920+ /// and otherwise ignore the request.
921+ clear_storage_request_sender : Sender < ( ) > ,
873922}
874923
875924impl ImapConnectionState {
@@ -881,11 +930,13 @@ impl ImapConnectionState {
881930 ) -> Result < ( Self , ImapConnectionHandlers ) > {
882931 let stop_token = CancellationToken :: new ( ) ;
883932 let ( idle_interrupt_sender, idle_interrupt_receiver) = channel:: bounded ( 1 ) ;
933+ let ( clear_storage_request_sender, clear_storage_request_receiver) = channel:: bounded ( 1 ) ;
884934
885935 let handlers = ImapConnectionHandlers {
886936 connection : Imap :: new ( context, transport_id, login_param, idle_interrupt_receiver)
887937 . await ?,
888938 stop_token : stop_token. clone ( ) ,
939+ clear_storage_request_receiver,
889940 } ;
890941
891942 let state = ConnectionState {
@@ -894,7 +945,10 @@ impl ImapConnectionState {
894945 connectivity : handlers. connection . connectivity . clone ( ) ,
895946 } ;
896947
897- let conn = ImapConnectionState { state } ;
948+ let conn = ImapConnectionState {
949+ state,
950+ clear_storage_request_sender,
951+ } ;
898952
899953 Ok ( ( conn, handlers) )
900954 }
@@ -908,10 +962,19 @@ impl ImapConnectionState {
908962 fn stop ( & self ) {
909963 self . state . stop ( ) ;
910964 }
965+
966+ /// Requests clearing relay storage and interrupts the inbox.
967+ fn clear_relay_storage ( & self ) {
968+ self . clear_storage_request_sender . try_send ( ( ) ) . ok ( ) ;
969+ self . state . interrupt ( ) ;
970+ }
911971}
912972
913973#[ derive( Debug ) ]
914974struct ImapConnectionHandlers {
915975 connection : Imap ,
916976 stop_token : CancellationToken ,
977+
978+ /// Channel receiver to get requests to clear IMAP storage.
979+ pub ( crate ) clear_storage_request_receiver : Receiver < ( ) > ,
917980}
0 commit comments