Show
Ignore:
Timestamp:
01/31/10 11:31:53 (2 years ago)
Author:
Mark Hammond <mhammond@…>
Branch:
default
Message:

better 'list' parsing; gmail xlist support; readonly select

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • imapclient/imapclient.py

    r130 r132  
    1616 
    1717from response_parser import parse_response, parse_fetch_response 
     18 
     19# We also offer the gmail-specific XLIST command... 
     20if 'XLIST' not in imaplib.Commands: 
     21  imaplib.Commands['XLIST'] = imaplib.Commands['LIST'] 
    1822 
    1923 
     
    6771 
    6872    re_sep = re.compile('^\(\("[^"]*" "([^"]+)"\)\)') 
    69 #     re_folder = re.compile('\([^)]*\) "[^"]+" "?([^"]+)"?') 
    70     re_folder = re.compile(r'\([^)]*\) "[^"]+" (?P<qqq>"?)(?P<folder>.+)(?P=qqq)') 
    7173    re_status = re.compile(r'^\s*"?(?P<folder>[^"]+)"?\s+' 
    7274                           r'\((?P<status_items>.*)\)$') 
     
    147149            raise self.Error('could not determine folder separator') 
    148150 
    149  
    150151    def list_folders(self, directory="", pattern="*"): 
    151152        """Get a listing of folders on the server. 
     
    157158        @param pattern: A pattern to match against folder names. Only folder 
    158159            names matching this pattern will be returned. Wildcards accepted. 
    159         @return: A list of folder names. Each folder name will be either a 
    160             string or a unicode string (if the folder on the server required 
    161             decoding). If the folder_encode attribute is False, no decoding 
    162             will be performed and only ordinary strings will be returned. 
    163         """ 
    164         typ, data = self._imap.list(directory, pattern) 
    165         self._checkok('list', typ, data) 
    166         return self._proc_folder_list(data) 
    167  
    168  
    169     def list_sub_folders(self, directory="", pattern="*"): 
    170         """Get a listing of subscribed folders on the server. 
    171  
    172         The default behaviour (no args) will list all subscribed folders for the 
    173         logged in user. 
     160        @return: A list of (flags, delim, folder_name). Each folder name will 
     161            be either a string or a unicode string (if the folder on the 
     162            server required decoding). If the folder_encode attribute is 
     163            False, no decoding will be performed and only ordinary strings 
     164            will be returned. 
     165        """ 
     166        return self._do_list('LIST', directory, pattern) 
     167 
     168    def xlist_folders(self, directory="", pattern="*"): 
     169        """A gmail-specific IMAP extension. 
     170         
     171        This method returns special flags for each folder and a localized name 
     172        for certain folders (eg, the name of the 'inbox' may be localized as the 
     173        flags can be used to determine the actual inbox, even if the name has 
     174        been localized.  It is the responsibility of the caller to either check 
     175        for 'XLIST' in the server capabilites, or to handle the error if the 
     176        server doesn't support this externsion. 
    174177 
    175178        @param directory: The base directory to look for folders from. 
    176179        @param pattern: A pattern to match against folder names. Only folder 
    177180            names matching this pattern will be returned. Wildcards accepted. 
    178         @return: A list of folder names. As per the return of list_folders(). 
    179         """ 
    180         typ, data = self._imap.lsub(directory, pattern) 
    181         self._checkok('lsub', typ, data) 
    182         return self._proc_folder_list(data) 
    183  
     181        @return: A list of (flags, delim, folder_name). As per the return of 
     182            list_folders(). 
     183        """ 
     184        return self._do_list('XLIST', directory, pattern) 
     185 
     186    def list_sub_folders(self, directory="", pattern="*"): 
     187        """Get a listing of subscribed folders on the server. 
     188 
     189        The default behaviour (no args) will list all subscribed folders for the 
     190        logged in user. 
     191 
     192        @param directory: The base directory to look for folders from. 
     193        @param pattern: A pattern to match against folder names. Only folder 
     194            names matching this pattern will be returned. Wildcards accepted. 
     195        @return: A list of (flags, delim, folder_name). As per the return of 
     196            list_folders(). 
     197        """ 
     198        return self._do_list('LSUB', directory, pattern) 
     199 
     200    def _do_list(self, cmd, directory, pattern): 
     201        typ, dat = self._imap._simple_command(cmd, directory, pattern) 
     202        self._checkok(cmd, typ, dat) 
     203        typ, dat = self._imap._untagged_response(typ, dat, cmd) 
     204        return self._proc_folder_list(dat) 
    184205 
    185206    def _proc_folder_list(self, folder_data): 
    186         folders = [] 
    187         for line in folder_data: 
    188             #TODO can the FetchParser code be adapted for use here? 
    189             folder_text = None 
    190             if isinstance(line, tuple): 
    191                 folder_text = line[-1] 
    192             elif line: 
    193                 match = self.re_folder.match(line) 
    194                 if match: 
    195                     folder_text = match.group('folder') 
    196                     folder_text = folder_text.replace(r'\"', '"') 
    197                     folder_text = folder_text.replace(r'\\', '\\') 
    198             if folder_text is not None: 
    199                 folders.append(self._decode_folder_name(folder_text)) 
    200         return folders 
    201          
    202  
    203     def select_folder(self, folder): 
     207        # appears to be a special case - no 'untagged' responses (ie, no 
     208        # folders) returns [None] 
     209        if folder_data == [None]: 
     210            return [] 
     211        ret = [] 
     212        parsed = parse_response(folder_data) 
     213        while parsed: 
     214            raw_flags, delim, raw_name = parsed[:3] 
     215            parsed = parsed[3:] 
     216            flags = [imap_utf7.decode(flag) for flag in raw_flags] 
     217            ret.append((flags, delim, self._decode_folder_name(raw_name))) 
     218        return ret 
     219 
     220    def select_folder(self, folder, readonly=False): 
    204221        """Select the current folder on the server. Future calls to methods 
    205222        such as search and fetch will act on the selected folder. 
     
    217234             'UIDVALIDITY': 1239278212} 
    218235        """ 
    219         typ, data = self._imap.select(self._encode_folder_name(folder)) 
     236        typ, data = self._imap.select(self._encode_folder_name(folder), readonly) 
    220237        self._checkok('select', typ, data) 
    221238        return self._process_select_response(self._imap.untagged_responses)