@@ -476,6 +476,27 @@ describe('IMAP Protocol integration tests', function () {
476476 ) ;
477477 } ) ;
478478
479+ it ( 'should default HIGHESTMODSEQ to 1 for a new mailbox' , function ( done ) {
480+ let cmds = [ 'T1 LOGIN testuser pass' , 'T2 CREATE modseqtest' , 'T3 SELECT modseqtest' , 'T4 STATUS modseqtest (HIGHESTMODSEQ)' , 'T5 LOGOUT' ] ;
481+
482+ testClient (
483+ {
484+ commands : cmds ,
485+ secure : true ,
486+ port
487+ } ,
488+ function ( resp ) {
489+ resp = resp . toString ( ) ;
490+ expect ( / ^ T 2 O K / m. test ( resp ) ) . to . be . true ;
491+ expect ( / ^ \* O K \[ H I G H E S T M O D S E Q 1 \] / m. test ( resp ) ) . to . be . true ;
492+ expect ( / ^ T 3 O K \[ R E A D - W R I T E \] / m. test ( resp ) ) . to . be . true ;
493+ expect ( / ^ \* S T A T U S m o d s e q t e s t \( H I G H E S T M O D S E Q 1 \) $ / m. test ( resp ) ) . to . be . true ;
494+ expect ( / ^ T 4 O K / m. test ( resp ) ) . to . be . true ;
495+ done ( ) ;
496+ }
497+ ) ;
498+ } ) ;
499+
479500 it ( `cannot create a mailbox with subpath length bigger than ${ MAX_MAILBOX_NAME_LENGTH } chars` , function ( done ) {
480501 let cmds = [
481502 'T1 LOGIN testuser pass' ,
@@ -1072,6 +1093,54 @@ describe('IMAP Protocol integration tests', function () {
10721093 }
10731094 ) ;
10741095 } ) ;
1096+
1097+ it ( 'should return MODIFIED when conditional STORE also targets expunged messages' , function ( done ) {
1098+ let mailbox = 'condstore-race' ;
1099+ let message = Buffer . from ( 'From: sender <[email protected] >\r\nTo: [email protected] \r\nSubject: HELLO!\r\n\r\nWORLD!' ) ; 1100+
1101+ let setupCmds = [ 'S1 LOGIN testuser pass' , 'S2 CREATE ' + mailbox ] ;
1102+ for ( let i = 0 ; i < 7 ; i ++ ) {
1103+ setupCmds . push ( 'S' + ( i + 3 ) + ' APPEND ' + mailbox + ' {' + message . length + '}\r\n' + message . toString ( 'binary' ) ) ;
1104+ }
1105+ setupCmds . push ( 'S10 SELECT ' + mailbox ) ;
1106+ setupCmds . push ( 'S11 STORE 2 +FLAGS (MyFlag1)' ) ;
1107+ setupCmds . push ( 'S12 LOGOUT' ) ;
1108+
1109+ let primaryCmds = [ 'A1 LOGIN testuser pass' , 'A2 SELECT ' + mailbox , 'SLEEP' , 'B001 STORE 1:7 (UNCHANGEDSINCE 7) +FLAGS (\\Seen)' , 'A4 LOGOUT' ] ;
1110+ let expungeCmds = [ 'C1 LOGIN testuser pass' , 'C2 SELECT ' + mailbox , 'C3 STORE 4:7 +FLAGS.SILENT (\\Deleted)' , 'C4 EXPUNGE' , 'C5 LOGOUT' ] ;
1111+
1112+ let runClient = commands =>
1113+ new Promise ( resolve => {
1114+ testClient (
1115+ {
1116+ commands,
1117+ secure : true ,
1118+ port
1119+ } ,
1120+ resp => resolve ( resp . toString ( ) )
1121+ ) ;
1122+ } ) ;
1123+
1124+ runClient ( setupCmds )
1125+ . then ( setupResp => {
1126+ expect ( / ^ S 1 1 O K / m. test ( setupResp ) ) . to . be . true ;
1127+
1128+ let primaryRun = runClient ( primaryCmds ) ;
1129+ let expungeRun = new Promise ( resolve => setTimeout ( resolve , 1000 ) ) . then ( ( ) => runClient ( expungeCmds ) ) ;
1130+
1131+ return Promise . all ( [ primaryRun , expungeRun ] ) ;
1132+ } )
1133+ . then ( ( [ primaryResp , expungeResp ] ) => {
1134+ expect ( / ^ C 4 O K / m. test ( expungeResp ) ) . to . be . true ;
1135+ expect ( primaryResp . match ( / ^ \* \d + F E T C H \( F L A G S \( \\ S e e n \) M O D S E Q \( \d + \) \) $ / gm) ) . to . have . length ( 2 ) ;
1136+ expect ( / ^ \* 1 F E T C H \( F L A G S \( \\ S e e n \) M O D S E Q \( \d + \) \) $ / m. test ( primaryResp ) ) . to . be . true ;
1137+ expect ( / ^ \* 3 F E T C H \( F L A G S \( \\ S e e n \) M O D S E Q \( \d + \) \) $ / m. test ( primaryResp ) ) . to . be . true ;
1138+ expect ( / ^ \* \d + E X P U N G E $ / m. test ( primaryResp ) ) . to . be . false ;
1139+ expect ( / ^ B 0 0 1 N O \[ M O D I F I E D 2 \] S o m e o f t h e m e s s a g e s n o l o n g e r e x i s t $ / m. test ( primaryResp ) ) . to . be . true ;
1140+ done ( ) ;
1141+ } )
1142+ . catch ( done ) ;
1143+ } ) ;
10751144 } ) ;
10761145
10771146 describe ( 'UID STORE' , function ( ) {
@@ -1312,8 +1381,8 @@ describe('IMAP Protocol integration tests', function () {
13121381 } ,
13131382 function ( resp ) {
13141383 resp = resp . toString ( ) ;
1315- expect ( resp . slice ( / \n / ) . indexOf ( ' * 3 FETCH (FLAGS (\\Seen) UID 103 MODSEQ (3))' ) >= 0 ) . to . be . true ; // UID FETCH FLAGS
1316- expect ( resp . slice ( / \n / ) . indexOf ( ' * 3 FETCH (FLAGS (\\Seen) MODSEQ (3))' ) >= 0 ) . to . be . true ; // FETCH FLAGS
1384+ expect ( / ^ \ * 3 F E T C H \ (F L A G S \ (\\ S e e n \ ) U I D 1 0 3 M O D S E Q \( 4 \) \) $ / m . test ( resp ) ) . to . be . true ; // UID FETCH FLAGS
1385+ expect ( / ^ \ * 3 F E T C H \ (F L A G S \ (\\ S e e n \ ) M O D S E Q \( 4 \) \) $ / m . test ( resp ) ) . to . be . true ; // FETCH FLAGS
13171386 expect ( resp . match ( / ^ \* \d + F E T C H / gm) . length ) . to . equal ( 2 ) ;
13181387 expect ( / ^ T 3 O K / m. test ( resp ) ) . to . be . true ;
13191388 expect ( / ^ T 4 O K / m. test ( resp ) ) . to . be . true ;
@@ -1324,6 +1393,25 @@ describe('IMAP Protocol integration tests', function () {
13241393 ) ;
13251394 } ) ;
13261395
1396+ it ( 'should enable CONDSTORE after FETCH MODSEQ' , function ( done ) {
1397+ let cmds = [ 'T1 LOGIN testuser pass' , 'T2 SELECT INBOX' , 'T3 FETCH 1 (MODSEQ)' , 'T4 STORE 1 +FLAGS (MyFlag1)' , 'T5 LOGOUT' ] ;
1398+
1399+ testClient (
1400+ {
1401+ commands : cmds ,
1402+ secure : true ,
1403+ port
1404+ } ,
1405+ function ( resp ) {
1406+ resp = resp . toString ( ) ;
1407+ expect ( / ^ \* 1 F E T C H \( M O D S E Q \( \d + \) \) $ / m. test ( resp ) ) . to . be . true ;
1408+ expect ( / ^ \* 1 F E T C H \( F L A G S \( M y F l a g 1 \) M O D S E Q \( \d + \) \) $ / m. test ( resp ) ) . to . be . true ;
1409+ expect ( / ^ T 4 O K / m. test ( resp ) ) . to . be . true ;
1410+ done ( ) ;
1411+ }
1412+ ) ;
1413+ } ) ;
1414+
13271415 describe ( 'Multiple values' , function ( ) {
13281416 it ( 'should list mixed data' , function ( done ) {
13291417 let cmds = [ 'T1 LOGIN testuser pass' , 'T2 SELECT INBOX' , 'T3 FETCH 1:* (UID BODYSTRUCTURE ENVELOPE)' , 'T4 LOGOUT' ] ;
0 commit comments