@@ -172,8 +172,7 @@ def append(self, mailbox, flags, date_time, message):
172172 date_time = Time2Internaldate (date_time )
173173 else :
174174 date_time = None
175- tag = self ._command (name , mailbox , flags , date_time , message )
176- return self ._command_complete (name , tag )
175+ return self ._simple_command (name , mailbox , flags , date_time , message )
177176
178177
179178 def authenticate (self , func ):
@@ -314,6 +313,8 @@ def lsub(self, directory='""', pattern='*'):
314313 def recent (self ):
315314 """Prompt server for an update.
316315
316+ Flush all untagged responses.
317+
317318 (typ, [data]) = <instance>.recent()
318319
319320 'data' is None if no new messages,
@@ -323,6 +324,7 @@ def recent(self):
323324 typ , dat = self ._untagged_response ('OK' , name )
324325 if dat [- 1 ]:
325326 return typ , dat
327+ self .untagged_responses = {}
326328 typ , dat = self ._simple_command ('NOOP' )
327329 return self ._untagged_response (typ , name )
328330
@@ -338,9 +340,11 @@ def rename(self, oldmailbox, newmailbox):
338340 def response (self , code ):
339341 """Return data for response 'code' if received, or None.
340342
343+ Old value for response 'code' is cleared.
344+
341345 (code, [data]) = <instance>.response(code)
342346 """
343- return code , self .untagged_responses . get (code , [ None ] )
347+ return self ._untagged_response (code , code )
344348
345349
346350 def search (self , charset , criteria ):
@@ -360,15 +364,14 @@ def search(self, charset, criteria):
360364 def select (self , mailbox = 'INBOX' , readonly = None ):
361365 """Select a mailbox.
362366
367+ Flush all untagged responses.
368+
363369 (typ, [data]) = <instance>.select(mailbox='INBOX', readonly=None)
364370
365371 'data' is count of messages in mailbox ('EXISTS' response).
366372 """
367373 # Mandated responses are ('FLAGS', 'EXISTS', 'RECENT', 'UIDVALIDITY')
368- # Remove immediately interesting responses
369- for r in ('EXISTS' , 'READ-WRITE' ):
370- if self .untagged_responses .has_key (r ):
371- del self .untagged_responses [r ]
374+ self .untagged_responses = {} # Flush old responses.
372375 if readonly :
373376 name = 'EXAMINE'
374377 else :
@@ -400,8 +403,7 @@ def store(self, message_set, command, flag_list):
400403
401404 (typ, [data]) = <instance>.store(message_set, command, flag_list)
402405 """
403- command = '%s %s' % (command , flag_list )
404- typ , dat = self ._simple_command ('STORE' , message_set , command )
406+ typ , dat = self ._simple_command ('STORE' , message_set , command , flag_list )
405407 return self ._untagged_response (typ , 'FETCH' )
406408
407409
@@ -413,16 +415,16 @@ def subscribe(self, mailbox):
413415 return self ._simple_command ('SUBSCRIBE' , mailbox )
414416
415417
416- def uid (self , command , args ):
417- """Execute "command args " with messages identified by UID,
418+ def uid (self , command , * args ):
419+ """Execute "command arg ... " with messages identified by UID,
418420 rather than message number.
419421
420- (typ, [data]) = <instance>.uid(command, args )
422+ (typ, [data]) = <instance>.uid(command, arg1, arg2, ... )
421423
422424 Returns response appropriate to 'command'.
423425 """
424426 name = 'UID'
425- typ , dat = self ._simple_command ('UID' , command , args )
427+ typ , dat = apply ( self ._simple_command , ('UID' , command ) + args )
426428 if command == 'SEARCH' :
427429 name = 'SEARCH'
428430 else :
@@ -440,15 +442,15 @@ def unsubscribe(self, mailbox):
440442 return self ._simple_command ('UNSUBSCRIBE' , mailbox )
441443
442444
443- def xatom (self , name , arg1 = None , arg2 = None ):
445+ def xatom (self , name , * args ):
444446 """Allow simple extension commands
445447 notified by server in CAPABILITY response.
446448
447- (typ, [data]) = <instance>.xatom(name, arg1=None, arg2=None )
449+ (typ, [data]) = <instance>.xatom(name, arg, ... )
448450 """
449451 if name [0 ] != 'X' or not name in self .capabilities :
450452 raise self .error ('unknown extension command: %s' % name )
451- return self ._simple_command (name , arg1 , arg2 )
453+ return apply ( self ._simple_command , (name ,) + args )
452454
453455
454456
@@ -475,7 +477,15 @@ def _command(self, name, dat1=None, dat2=None, dat3=None, literal=None):
475477 tag = self ._new_tag ()
476478 data = '%s %s' % (tag , name )
477479 for d in (dat1 , dat2 , dat3 ):
478- if d is not None : data = '%s %s' % (data , d )
480+ if d is None : continue
481+ if type (d ) is type ('' ):
482+ l = len (string .split (d ))
483+ else :
484+ l = 1
485+ if l == 0 or l > 1 and (d [0 ],d [- 1 ]) not in (('(' ,')' ),('"' ,'"' )):
486+ data = '%s "%s"' % (data , d )
487+ else :
488+ data = '%s %s' % (data , d )
479489 if literal is not None :
480490 data = '%s {%s}' % (data , len (literal ))
481491
@@ -529,11 +539,9 @@ def _get_response(self):
529539 # Read response and store.
530540 #
531541 # Returns None for continuation responses,
532- # otherwise first response line received
542+ # otherwise first response line received.
533543
534- # Protocol mandates all lines terminated by CRLF.
535-
536- resp = self ._get_line ()[:- 2 ]
544+ resp = self ._get_line ()
537545
538546 # Command completion response?
539547
@@ -584,7 +592,7 @@ def _get_response(self):
584592
585593 # Read trailer - possibly containing another literal
586594
587- dat = self ._get_line ()[: - 2 ]
595+ dat = self ._get_line ()
588596
589597 self ._append_untagged (typ , dat )
590598
@@ -614,8 +622,9 @@ def _get_line(self):
614622
615623 # Protocol mandates all lines terminated by CRLF
616624
625+ line = line [:- 2 ]
617626 if __debug__ and self .debug >= 4 :
618- print '\t < %s' % line [: - 2 ]
627+ print '\t < %s' % line
619628 return line
620629
621630
@@ -638,16 +647,18 @@ def _new_tag(self):
638647 return tag
639648
640649
641- def _simple_command (self , name , dat1 = None , dat2 = None ):
650+ def _simple_command (self , name , * args ):
642651
643- return self ._command_complete (name , self ._command (name , dat1 , dat2 ))
652+ return self ._command_complete (name , apply ( self ._command , (name ,) + args ))
644653
645654
646655 def _untagged_response (self , typ , name ):
647656
648657 if not self .untagged_responses .has_key (name ):
649658 return typ , [None ]
650659 data = self .untagged_responses [name ]
660+ if __debug__ and self .debug >= 5 :
661+ print '\t untagged_responses[%s] => %.20s..' % (name , `data` )
651662 del self .untagged_responses [name ]
652663 return typ , data
653664
@@ -755,25 +766,25 @@ def Time2Internaldate(date_time):
755766
756767 test_seq1 = (
757768 ('login' , (USER , PASSWD )),
758- ('create' , ('/tmp/xxx' ,)),
759- ('rename' , ('/tmp/xxx' , '/tmp/yyy' )),
760- ('CREATE' , ('/tmp/yyz' ,)),
761- (
'append' , (
'/tmp/yyz' ,
None ,
None ,
'From: [email protected] \n \n data...' )),
762- ('select' , ('/tmp/yyz' ,)),
763- ('recent' , ()),
769+ ('create' , ('/tmp/xxx 1' ,)),
770+ ('rename' , ('/tmp/xxx 1' , '/tmp/yyy' )),
771+ ('CREATE' , ('/tmp/yyz 2' ,)),
772+ (
'append' , (
'/tmp/yyz 2' ,
None ,
None ,
'From: [email protected] \n \n data...' )),
773+ ('select' , ('/tmp/yyz 2' ,)),
764774 ('uid' , ('SEARCH' , 'ALL' )),
765775 ('fetch' , ('1' , '(INTERNALDATE RFC822)' )),
766776 ('store' , ('1' , 'FLAGS' , '(\Deleted)' )),
767777 ('expunge' , ()),
778+ ('recent' , ()),
768779 ('close' , ()),
769780 )
770781
771782 test_seq2 = (
772783 ('select' , ()),
773784 ('response' ,('UIDVALIDITY' ,)),
774785 ('uid' , ('SEARCH' , 'ALL' )),
775- ('recent' , ()),
776786 ('response' , ('EXISTS' ,)),
787+ ('recent' , ()),
777788 ('logout' , ()),
778789 )
779790
@@ -790,7 +801,9 @@ def run(cmd, args):
790801 run (cmd , args )
791802
792803 for ml in run ('list' , ('/tmp/' , 'yy%' )):
793- path = string .split (ml )[- 1 ]
804+ mo = re .match (r'.*"([^"]+)"$' , ml )
805+ if mo : path = mo .group (1 )
806+ else : path = string .split (ml )[- 1 ]
794807 run ('delete' , (path ,))
795808
796809 for cmd ,args in test_seq2 :
@@ -800,5 +813,5 @@ def run(cmd, args):
800813 continue
801814
802815 uid = string .split (dat [0 ])[- 1 ]
803- run ('uid' , ('FETCH' ,
804- '%s (FLAGS INTERNALDATE RFC822.SIZE RFC822.HEADER RFC822)' % uid ))
816+ run ('uid' , ('FETCH' , '%s' % uid ,
817+ '(FLAGS INTERNALDATE RFC822.SIZE RFC822.HEADER RFC822)' ))
0 commit comments