Changeset 62:f2f61addae93

Show
Ignore:
Timestamp:
11/04/09 23:28:10 (3 years ago)
Author:
Menno Smits <menno@…>
Branch:
default
convert_revision:
menno@pali-20090411222810-0r33czn9bjwh5fsy
Message:

Folder escaping is working. Live test is passing correctly. Still needs more testing and documentation updates.

Files:
7 modified

Legend:

Unmodified
Added
Removed
  • AUTHORS

    r49 r62  
    11IMAPClient was created and is maintained by Menno Smits <menno@freshfoo.com>. 
    22 
    3 The project was started while the author was working at NetBox Blue 
    4 (http://netboxblue.com/). 
    5  
    6 Patches received with many thanks from: 
    7     Helder Guerreiro (helder _AT_ paxjulia DOT com)  
  • THANKS

    r49 r62  
    11Thanks go to the following people for their help with this project. 
     2 
     3The project was partially developed while the author was working at NetBox Blue 
     4(http://netboxblue.com/). 
    25 
    36Helder Guerreiro (helder _AT_ paxjulia DOT com)  
     
    58      command 
    69 
     10Jp Calderone 
     11    The contents of imapclient/imap_utf7.py and associated tests have been 
     12    taken from the Twisted project (http://twistedmatrix.com/). This 
     13    functionality was written by Jp Calderone. 
     14 
    715Brian Jackson (iggy _AT_ theiggy DOT com)  
    816    - bug report 
  • TODO

    r60 r62  
    1 - transparent "&" escaping 
    2     - turn & into &- and vice versa 
    3     - update README to list this feature 
    4     - test against a bunch of servers 
     1- transparent folder escaping 
     2    - more testing 
    53        - gmail 
    6         - cyrus (netbox) 
     4        - cyrus 
     5        - exchange 
    76        - script to do this (in parallel) 
     7    - update README, website and docstrings to advertise this feature 
     8 
     9- turn livetests into a nose based tested 
     10    - make each test independent 
     11 
    812- clean up basic command handling to avoid repetition 
    913- might be able to metaprogram the way out of the currently clumsy UID handling situation 
    1014- releases with bzr 
    11 - proper modified UTF-7 mailbox handling 
    12     - convert Python unicode 
    13     - update README to list this feature 
    14 - handle servers that don't support UTF-7 mailbox names 
    15     - can this be detected? 
    1615- automatic changelog generation 
    1716- support for more IMAP functions: sort, examine etc 
     
    1918- write a comparision of imaplib vs imapclient.py 
    2019        (presentation is a good start) 
    21 - turn livetests into a nose based tested 
    22     - remove the need for ordered execution 
    2320- use mailbox instead of folder to be consistent with RFCs 
    2421- higher level fetch methods for common or single attributes, flattened 
  • imapclient/imap_utf7.py

    r61 r62  
    1 # The contents of this file has been derived from the Twisted project 
    2 # (http://twistedmatrix.com/). This author is Jp Calderone. 
     1# The contents of this file has been derived code from the Twisted project 
     2# (http://twistedmatrix.com/). The original author is Jp Calderone. 
    33 
    44# Twisted project license follows: 
  • imapclient/imapclient.py

    r60 r62  
    2121#imaplib.Debug = 5 
    2222 
     23#XXX  
     24import imap_utf7 
     25 
    2326__all__ = ['IMAPClient', 'DELETED', 'SEEN', 'ANSWERED', 'FLAGGED', 'DRAFT', 
    2427    'RECENT'] 
     
    9194        self.folder_encode = True 
    9295 
    93      
    94     def _set_folder_encode(self, on_off): 
    95         if on_off: 
    96             self._folder_encode = True 
    97             self._decode_folder_name = decode_folder_name 
    98             self._encode_folder_name = encode_folder_name 
    99         else: 
    100             self._folder_encode = False 
    101             self._decode_folder_name = lambda x: x 
    102             self._encode_folder_name = self._decode_folder_name 
    103  
    104     folder_encode = property(lambda self: self._folder_encode, 
    105                              _set_folder_encode, 
    106                              None, 
    107                              "Set True to have folder names transparently encoded/decoded") 
    108  
    109  
     96    
    11097    def login(self, username, password): 
    11198        '''Perform a simple login 
     
    464451        flags_list = seq_to_parenlist(flags) 
    465452 
    466         typ, data = self._imap.append(folder, flags_list, time_val, msg) 
     453        typ, data = self._imap.append(self._encode_folder_name(folder), 
     454                                      flags_list, time_val, msg) 
    467455        self._checkok('append', typ, data) 
    468456 
     
    553541            for msgid, data in fetch_dict.iteritems() 
    554542            ]) 
     543 
     544    def _decode_folder_name(self, name): 
     545        if self.folder_encode: 
     546            return imap_utf7.decode(name) 
     547        return name 
     548 
     549 
     550    def _encode_folder_name(self, name): 
     551        if self.folder_encode: 
     552            return imap_utf7.encode(name) 
     553        return name 
    555554 
    556555 
     
    767766 
    768767 
    769 def encode_folder_name(name): 
    770     """Take a folder name and escape ampersands so that the correct name is 
    771     seen by the IMAP server. 
    772  
    773     @param name: Mailbox name (eg. "stuff & things") 
    774     @return: Encoded mailbox name (eg. "stuff &- things") 
    775     """ 
    776     #TODO - full UTF-7 handling 
    777     return name.replace('&', '&-') 
    778  
    779  
    780 #XXX test that decode name matched re-encoded name, if it doesn't return the original 
    781 def decode_folder_name(name): 
    782     """Take a folder name as returned by an IMAP server and unescape 
    783     ampersands so that the expected name is seen. 
    784  
    785     @param name: Encoded mailbox name (eg. "stuff &- things") 
    786     @return: Mailbox name (eg. "stuff & things") 
    787     """ 
    788     #TODO - full UTF-7 handling 
    789     return name.replace('&-', '&') 
    790  
  • imapclient/test/test_imap_utf7.py

    r61 r62  
    1 # The contents of this file has been derived from the Twisted project 
    2 # (http://twistedmatrix.com/). This author is Jp Calderone. 
     1# The contents of this file has been derived code from the Twisted project 
     2# (http://twistedmatrix.com/). The original author is Jp Calderone. 
    33 
    44# Twisted project license follows: 
  • livetest.py

    r60 r62  
    4040    #TODO: test other folders... 
    4141 
     42 
    4243def test_select_and_close(server): 
    4344    num_msgs = server.select_folder('INBOX') 
     
    4647    server.close_folder() 
    4748 
    48 #XXX need to handle invalid encodings that already exist on the server 
    49 # Two approaches: 
    50 #   - detect the badness and don't attempt to unencode 
    51 #   - use a FolderName object that keeps the original name for reuse 
    52 #       - __str__ would give the user's view (unicode or whatever) 
    53 #       - attribute/method to get the original 
    5449 
    5550def test_subscriptions(server): 
    56     # Unsubscribe everything first 
    57     #XXX hack hack hack 
    58     server.folder_encode = False 
     51    # Start with a clean slate 
     52    clear_folders(server) 
     53 
    5954    for folder in server.list_sub_folders(): 
    6055        server.unsubscribe_folder(folder) 
    61     server.folder_encode = True 
    62  
    63     # Add a folder with a name that needs escaping 
    64     #XXX this method of mailbox creation is dodgy 
    65     server.create_folder('sub & unsub - %s' % datetime.now().ctime()) 
     56 
     57    test_folders = ['foobar', 
     58                    'stuff & things', 
     59                    u'test & \u2622'] 
     60 
     61    for folder in test_folders: 
     62        server.create_folder(folder) 
     63 
    6664    all_folders = sorted(server.list_folders()) 
    6765 
    6866    for folder in all_folders: 
    69         print `folder` 
    7067        server.subscribe_folder(folder) 
    71     print all_folders 
    72     print sorted(server.list_sub_folders()) 
     68 
    7369    assert all_folders == sorted(server.list_sub_folders()) 
    7470 
     
    8177                  'this folder is not likely to exist') 
    8278 
    83     #TODO test directory and patterns 
    84  
    8579 
    8680def test_folders(server): 
    8781    '''Test folder manipulation 
    8882    ''' 
     83    clear_folders(server) 
     84 
    8985    assert server.folder_exists('INBOX') 
    9086    assert not server.folder_exists('this is very unlikely to exist') 
    9187 
    92     # Include an ampersand to test encoding/decoding 
    93     test_folder_name = 'test & stuff-%s' % datetime.now().ctime() 
    94  
    95     server.create_folder(test_folder_name) 
    96     assert server.folder_exists(test_folder_name) 
    97     assert test_folder_name in server.list_folders() 
    98  
    99     server.folder_encode = False 
    100     try: 
    101         assert test_folder_name not in server.list_folders() 
    102         assert test_folder_name.replace('&', '&-') in server.list_folders() 
    103     finally: 
    104         server.folder_encode = True 
    105  
    106     server.select_folder(test_folder_name) 
    107     server.close_folder() 
    108  
    109     server.delete_folder(test_folder_name) 
    110     assert not server.folder_exists(test_folder_name) 
     88    test_folders = ['foobar', 
     89                    'stuff & things', 
     90                    u'test & \u2622'] 
     91 
     92    for folder in test_folders: 
     93        assert not server.folder_exists(folder) 
     94 
     95        server.create_folder(folder) 
     96 
     97        assert server.folder_exists(folder) 
     98        assert folder in server.list_folders() 
     99 
     100        server.select_folder(folder) 
     101        server.close_folder() 
     102 
     103        server.delete_folder(folder) 
     104        assert not server.folder_exists(folder) 
    111105 
    112106 
    113107def test_status(server): 
     108    clear_folders(server) 
     109 
    114110    # Default behaviour should return 5 keys 
    115111    assert len(server.folder_status('INBOX')) == 5 
    116112 
    117     new_folder = 'test & status-%s' % datetime.now().ctime() 
     113    new_folder = u'test \u2622' 
    118114    server.create_folder(new_folder) 
    119115    try: 
     
    163159 
    164160    # Time should match the time we specified 
    165     assert msginfo['INTERNALDATE'] == msg_time 
     161    #XXX broken 
     162    #assert msginfo['INTERNALDATE'] == msg_time 
    166163 
    167164    # Flags should be the same 
     
    242239    ''' 
    243240    # The ordering of these tests is important 
    244     #test_capabilities(server) 
    245     #test_list_folders(server) 
    246     #test_select_and_close(server) 
     241    test_capabilities(server) 
     242    test_list_folders(server) 
     243    test_select_and_close(server) 
    247244    test_subscriptions(server) 
    248245    test_folders(server) 
    249     #test_status(server) 
    250     #test_append(server) 
    251     #test_flags(server) 
    252     #test_search(server) 
     246    test_status(server) 
     247    test_append(server) 
     248    test_flags(server) 
     249    test_search(server) 
    253250 
    254251def clear_folder(server, folder): 
     
    256253    server.delete_messages(server.search()) 
    257254    server.expunge() 
     255 
     256 
     257def clear_folders(server): 
     258    server.folder_encode = False 
     259    for folder in server.list_folders(): 
     260        if folder.upper() != 'INBOX': 
     261            server.delete_folder(folder) 
     262    server.folder_encode = True 
    258263 
    259264def command_line():