@@ -570,9 +570,7 @@ class IMAPConnection extends EventEmitter {
570570 let isSelected = mailbox => mailbox && conn . selected && conn . selected . mailbox && conn . selected . mailbox . toString ( ) === mailbox . toString ( ) ;
571571
572572 this . _listenerData = {
573- lock : false ,
574573 cleared : false ,
575- pendingUpdate : false ,
576574 callback ( message ) {
577575 let selectedMailbox = conn . selected && conn . selected . mailbox ;
578576 if ( conn . _closing || conn . _closed ) {
@@ -604,29 +602,11 @@ class IMAPConnection extends EventEmitter {
604602 return ;
605603 }
606604
607- if ( conn . _listenerData . lock ) {
608- // Mark that we received a notification while locked, will re-check after lock is released
609- conn . _listenerData . pendingUpdate = true ;
610- return ;
611- }
612-
613- conn . _listenerData . lock = true ;
614- conn . _listenerData . pendingUpdate = false ;
615-
616605 conn . _server . notifier . getUpdates ( selectedMailbox , conn . selected . modifyIndex , ( err , updates ) => {
617606 if ( ! conn . _listenerData || conn . _listenerData . cleared ) {
618607 // already logged out
619608 return ;
620609 }
621- conn . _listenerData . lock = false ;
622-
623- // Helper to re-check if we missed notifications while locked
624- let recheckPending = ( ) => {
625- if ( conn . _listenerData && ! conn . _listenerData . cleared && conn . _listenerData . pendingUpdate ) {
626- conn . _listenerData . pendingUpdate = false ;
627- setImmediate ( ( ) => conn . _listenerData . callback ( ) ) ;
628- }
629- } ;
630610
631611 if ( err ) {
632612 conn . logger . info (
@@ -639,13 +619,11 @@ class IMAPConnection extends EventEmitter {
639619 conn . id ,
640620 err . message
641621 ) ;
642- recheckPending ( ) ;
643622 return ;
644623 }
645624
646625 // check if the same mailbox is still selected
647626 if ( ! isSelected ( selectedMailbox ) || ! updates || ! updates . length ) {
648- recheckPending ( ) ;
649627 return ;
650628 }
651629
@@ -656,14 +634,28 @@ class IMAPConnection extends EventEmitter {
656634 conn . selected . modifyIndex = updates [ updates . length - 1 ] . modseq ;
657635 }
658636
659- // append received notifications to the list
660- conn . selected . notifications = conn . selected . notifications . concat ( updates ) ;
637+ if ( ! conn . selected . notificationQueueKeys ) {
638+ conn . selected . notificationQueueKeys = new Set ( ) ;
639+ }
640+
641+ let queued = 0 ;
642+ for ( let update of updates ) {
643+ let key = update && update . _id ? update . _id . toString ( ) : '' ;
644+ if ( ! key || conn . selected . notificationQueueKeys . has ( key ) ) {
645+ continue ;
646+ }
647+
648+ conn . selected . notificationQueueKeys . add ( key ) ;
649+ conn . selected . notifications . push ( update ) ;
650+ queued ++ ;
651+ }
652+
661653 if ( conn . idling ) {
662654 // when idling emit notifications immediately
663- conn . emitNotifications ( ) ;
655+ if ( queued ) {
656+ conn . emitNotifications ( ) ;
657+ }
664658 }
665-
666- recheckPending ( ) ;
667659 } ) ;
668660 }
669661 } ;
@@ -682,7 +674,24 @@ class IMAPConnection extends EventEmitter {
682674
683675 // send notifications to client
684676 emitNotifications ( ) {
685- if ( this . state !== 'Selected' || ! this . selected || ! this . selected . notifications . length ) {
677+ if ( this . state !== 'Selected' || ! this . selected ) {
678+ return ;
679+ }
680+
681+ let notifications = this . selected . notifications || [ ] ;
682+ this . selected . notifications = [ ] ;
683+
684+ if ( this . selected . notificationQueueKeys && notifications . length ) {
685+ for ( let i = 0 , len = notifications . length ; i < len ; i ++ ) {
686+ let update = notifications [ i ] ;
687+ let key = update && update . _id ? update . _id . toString ( ) : '' ;
688+ if ( key ) {
689+ this . selected . notificationQueueKeys . delete ( key ) ;
690+ }
691+ }
692+ }
693+
694+ if ( ! notifications . length ) {
686695 return ;
687696 }
688697
@@ -697,16 +706,16 @@ class IMAPConnection extends EventEmitter {
697706 } ,
698707 '[%s] Pending notifications: %s' ,
699708 this . id ,
700- this . selected . notifications . length
709+ notifications . length
701710 ) ;
702711
703712 // find UIDs that are both added and removed
704713 let added = new Set ( ) ; // added UIDs
705714 let removed = new Set ( ) ; // removed UIDs
706715 let skip = new Set ( ) ; // UIDs that are removed before ever seen
707716
708- for ( let i = 0 , len = this . selected . notifications . length ; i < len ; i ++ ) {
709- let update = this . selected . notifications [ i ] ;
717+ for ( let i = 0 , len = notifications . length ; i < len ; i ++ ) {
718+ let update = notifications [ i ] ;
710719 if ( update . command === 'EXISTS' ) {
711720 added . add ( update . uid ) ;
712721 } else if ( update . command === 'EXPUNGE' ) {
@@ -722,20 +731,20 @@ class IMAPConnection extends EventEmitter {
722731
723732 // filter multiple FETCH calls, only keep latest, otherwise might mess up MODSEQ responses
724733 let fetches = new Set ( ) ;
725- for ( let i = this . selected . notifications . length - 1 ; i >= 0 ; i -- ) {
726- let update = this . selected . notifications [ i ] ;
734+ for ( let i = notifications . length - 1 ; i >= 0 ; i -- ) {
735+ let update = notifications [ i ] ;
727736 if ( update . command === 'FETCH' ) {
728737 // skip multiple flag updates and updates for removed or newly added messages
729738 if ( fetches . has ( update . uid ) || added . has ( update . uid ) || removed . has ( update . uid ) ) {
730- this . selected . notifications . splice ( i , 1 ) ;
739+ notifications . splice ( i , 1 ) ;
731740 } else {
732741 fetches . add ( update . uid ) ;
733742 }
734743 }
735744 }
736745
737- for ( let i = 0 , len = this . selected . notifications . length ; i < len ; i ++ ) {
738- let update = this . selected . notifications [ i ] ;
746+ for ( let i = 0 , len = notifications . length ; i < len ; i ++ ) {
747+ let update = notifications [ i ] ;
739748
740749 // skip unnecessary entries that are already removed
741750 if ( skip . has ( update . uid ) ) {
@@ -828,9 +837,6 @@ class IMAPConnection extends EventEmitter {
828837 ]
829838 } ) ;
830839 }
831-
832- // clear queue
833- this . selected . notifications = [ ] ;
834840 }
835841
836842 formatResponse ( command , uid , data ) {
0 commit comments