@@ -590,13 +590,17 @@ def close(self):
590590 return typ , dat
591591
592592
593- def copy (self , message_set , new_mailbox ):
593+ def copy (self , message_set , new_mailbox , * , uid = False ):
594594 """Copy 'message_set' messages onto end of 'new_mailbox'.
595595
596596 (typ, [data]) = <instance>.copy(message_set, new_mailbox)
597+
598+ If 'uid' is true, 'message_set' is a set of UIDs (UID COPY).
597599 """
598- return self ._simple_command ('COPY' , self ._sequence_set (message_set ),
599- self ._mailbox (new_mailbox ))
600+ args = (self ._sequence_set (message_set ), self ._mailbox (new_mailbox ))
601+ if uid :
602+ return self ._simple_command ('UID' , self ._atom ('COPY' ), * args )
603+ return self ._simple_command ('COPY' , * args )
600604
601605
602606 def create (self , mailbox ):
@@ -634,21 +638,34 @@ def enable(self, capability):
634638 self ._mode_utf8 ()
635639 return typ , data
636640
637- def expunge (self ):
641+ def expunge (self , message_set = None , * , uid = False ):
638642 """Permanently remove deleted items from selected mailbox.
639643
640644 Generates 'EXPUNGE' response for each deleted message.
641645
642646 (typ, [data]) = <instance>.expunge()
643647
644648 'data' is list of 'EXPUNGE'd message numbers in order received.
649+
650+ If 'uid' is true, only messages with a UID in 'message_set' are
651+ removed (UID EXPUNGE, RFC 4315); 'message_set' is then required and
652+ must be omitted otherwise.
645653 """
646654 name = 'EXPUNGE'
647- typ , dat = self ._simple_command (name )
655+ if uid :
656+ if message_set is None :
657+ raise self .error ('UID EXPUNGE requires a message set' )
658+ typ , dat = self ._simple_command ('UID' , self ._atom (name ),
659+ self ._sequence_set (message_set ))
660+ else :
661+ if message_set is not None :
662+ raise self .error ('EXPUNGE takes no message set; '
663+ 'use uid=True for UID EXPUNGE' )
664+ typ , dat = self ._simple_command (name )
648665 return self ._untagged_response (typ , dat , name )
649666
650667
651- def fetch (self , message_set , message_parts ):
668+ def fetch (self , message_set , message_parts , * , uid = False ):
652669 """Fetch (parts of) messages.
653670
654671 (typ, [data, ...]) = <instance>.fetch(message_set, message_parts)
@@ -657,10 +674,17 @@ def fetch(self, message_set, message_parts):
657674 enclosed in parentheses, eg: "(UID BODY[TEXT])".
658675
659676 'data' are tuples of message part envelope and data.
677+
678+ If 'uid' is true, 'message_set' is a set of UIDs and the message
679+ numbers in the response are UIDs (UID FETCH).
660680 """
661681 name = 'FETCH'
662- typ , dat = self ._simple_command (name , self ._sequence_set (message_set ),
663- self ._fetch_parts (message_parts ))
682+ args = (self ._sequence_set (message_set ),
683+ self ._fetch_parts (message_parts ))
684+ if uid :
685+ typ , dat = self ._simple_command ('UID' , self ._atom (name ), * args )
686+ else :
687+ typ , dat = self ._simple_command (name , * args )
664688 return self ._untagged_response (typ , dat , name )
665689
666690
@@ -842,13 +866,17 @@ def lsub(self, directory='', pattern='*'):
842866 self ._list_mailbox (pattern ))
843867 return self ._untagged_response (typ , dat , name )
844868
845- def move (self , message_set , new_mailbox ):
869+ def move (self , message_set , new_mailbox , * , uid = False ):
846870 """Move 'message_set' messages onto end of 'new_mailbox'.
847871
848872 (typ, [data]) = <instance>.move(message_set, new_mailbox)
873+
874+ If 'uid' is true, 'message_set' is a set of UIDs (UID MOVE).
849875 """
850- return self ._simple_command ('MOVE' , self ._sequence_set (message_set ),
851- self ._mailbox (new_mailbox ))
876+ args = (self ._sequence_set (message_set ), self ._mailbox (new_mailbox ))
877+ if uid :
878+ return self ._simple_command ('UID' , self ._atom ('MOVE' ), * args )
879+ return self ._simple_command ('MOVE' , * args )
852880
853881 def myrights (self , mailbox ):
854882 """Show my ACLs for a mailbox (i.e. the rights that I have on mailbox).
@@ -913,22 +941,27 @@ def rename(self, oldmailbox, newmailbox):
913941 self ._mailbox (newmailbox ))
914942
915943
916- def search (self , charset , * criteria ):
944+ def search (self , charset , * criteria , uid = False ):
917945 """Search mailbox for matching messages.
918946
919947 (typ, [data]) = <instance>.search(charset, criterion, ...)
920948
921949 'data' is space separated list of matching message numbers.
922950 If UTF8 is enabled, charset MUST be None.
951+ If 'uid' is true, the message numbers in the response are UIDs
952+ (UID SEARCH).
923953 """
924954 name = 'SEARCH'
925955 if charset is not None :
926956 if self .utf8_enabled :
927957 raise IMAP4 .error ("Non-None charset not valid in UTF8 mode" )
928- typ , dat = self ._simple_command (name ,
929- 'CHARSET' , self ._astring (charset ), * criteria )
958+ args = ('CHARSET' , self ._astring (charset ), * criteria )
930959 else :
931- typ , dat = self ._simple_command (name , * criteria )
960+ args = criteria
961+ if uid :
962+ typ , dat = self ._simple_command ('UID' , self ._atom (name ), * args )
963+ else :
964+ typ , dat = self ._simple_command (name , * args )
932965 return self ._untagged_response (typ , dat , name )
933966
934967
@@ -991,18 +1024,25 @@ def setquota(self, root, limits):
9911024 return self ._untagged_response (typ , dat , 'QUOTA' )
9921025
9931026
994- def sort (self , sort_criteria , charset , * search_criteria ):
1027+ def sort (self , sort_criteria , charset , * search_criteria , uid = False ):
9951028 """IMAP4rev1 extension SORT command.
9961029
9971030 (typ, [data]) = <instance>.sort(sort_criteria, charset, search_criteria, ...)
1031+
1032+ If 'uid' is true, the message numbers in the response are UIDs
1033+ (UID SORT).
9981034 """
9991035 name = 'SORT'
10001036 #if not name in self.capabilities: # Let the server decide!
10011037 # raise self.error('unimplemented extension command: %s' % name)
10021038 sort_criteria = self ._set_quote (sort_criteria )
10031039 if charset is not None :
10041040 charset = self ._astring (charset )
1005- typ , dat = self ._simple_command (name , sort_criteria , charset , * search_criteria )
1041+ args = (sort_criteria , charset , * search_criteria )
1042+ if uid :
1043+ typ , dat = self ._simple_command ('UID' , self ._atom (name ), * args )
1044+ else :
1045+ typ , dat = self ._simple_command (name , * args )
10061046 return self ._untagged_response (typ , dat , name )
10071047
10081048
@@ -1043,14 +1083,20 @@ def status(self, mailbox, names):
10431083 return self ._untagged_response (typ , dat , name )
10441084
10451085
1046- def store (self , message_set , command , flags ):
1086+ def store (self , message_set , command , flags , * , uid = False ):
10471087 """Alters flag dispositions for messages in mailbox.
10481088
10491089 (typ, [data]) = <instance>.store(message_set, command, flags)
1090+
1091+ If 'uid' is true, 'message_set' is a set of UIDs (UID STORE).
10501092 """
1051- flags = self ._set_quote (flags )
1052- typ , dat = self ._simple_command ('STORE' , self ._sequence_set (message_set ),
1053- command , flags )
1093+ name = 'STORE'
1094+ args = (self ._sequence_set (message_set ), command ,
1095+ self ._set_quote (flags ))
1096+ if uid :
1097+ typ , dat = self ._simple_command ('UID' , self ._atom (name ), * args )
1098+ else :
1099+ typ , dat = self ._simple_command (name , * args )
10541100 return self ._untagged_response (typ , dat , 'FETCH' )
10551101
10561102
@@ -1062,16 +1108,22 @@ def subscribe(self, mailbox):
10621108 return self ._simple_command ('SUBSCRIBE' , self ._mailbox (mailbox ))
10631109
10641110
1065- def thread (self , threading_algorithm , charset , * search_criteria ):
1111+ def thread (self , threading_algorithm , charset , * search_criteria , uid = False ):
10661112 """IMAPrev1 extension THREAD command.
10671113
10681114 (type, [data]) = <instance>.thread(threading_algorithm, charset, search_criteria, ...)
1115+
1116+ If 'uid' is true, the message numbers in the response are UIDs
1117+ (UID THREAD).
10691118 """
10701119 name = 'THREAD'
10711120 if charset is not None :
10721121 charset = self ._astring (charset )
1073- typ , dat = self ._simple_command (name , self ._atom (threading_algorithm ),
1074- charset , * search_criteria )
1122+ args = (self ._atom (threading_algorithm ), charset , * search_criteria )
1123+ if uid :
1124+ typ , dat = self ._simple_command ('UID' , self ._atom (name ), * args )
1125+ else :
1126+ typ , dat = self ._simple_command (name , * args )
10751127 return self ._untagged_response (typ , dat , name )
10761128
10771129
0 commit comments