Ticket #5697: 5697-imap4client-20120612.patch

File 5697-imap4client-20120612.patch, 7.0 KB (added by argonemyth, 3 years ago)
  • doc/mail/examples/imap4client.py

     
    2020from twisted.python import util 
    2121from twisted.python import log 
    2222 
     23 
     24 
    2325class TrivialPrompter(basic.LineReceiver): 
    2426    from os import linesep as delimiter 
    2527 
     
    4042        d, self.promptDeferred = self.promptDeferred, None 
    4143        d.callback(line) 
    4244 
     45 
     46 
    4347class SimpleIMAP4Client(imap4.IMAP4Client): 
     48    """ 
     49    Add callbacks when the client receives greeting messages from 
     50    an IMAP server. 
     51    """ 
    4452    greetDeferred = None 
    4553     
    4654    def serverGreeting(self, caps): 
     
    4957            d, self.greetDeferred = self.greetDeferred, None 
    5058            d.callback(self) 
    5159 
     60 
     61 
    5262class SimpleIMAP4ClientFactory(protocol.ClientFactory): 
    5363    usedUp = False 
    5464 
    5565    protocol = SimpleIMAP4Client 
    5666 
     67 
    5768    def __init__(self, username, onConn): 
    5869        self.ctx = ssl.ClientContextFactory() 
    5970         
    6071        self.username = username 
    6172        self.onConn = onConn 
    6273 
     74 
    6375    def buildProtocol(self, addr): 
     76        """ 
     77        Initiate the protocol instance. Since we are building a simple 
     78        IMAP client, we don't bother checking what capabilities the server 
     79        has. We just add all the authenticators twisted.mail has. 
     80        Note: Gmail no longer uses any of the method below, it's been 
     81        using XOAUTH since 2010.  
     82        """ 
    6483        assert not self.usedUp 
    6584        self.usedUp = True 
    6685         
     
    6887        p.factory = self 
    6988        p.greetDeferred = self.onConn 
    7089 
    71         auth = imap4.CramMD5ClientAuthenticator(self.username) 
    72         p.registerAuthenticator(auth) 
    73          
     90        p.registerAuthenticator(imap4.PLAINAuthenticator(self.username)) 
     91        p.registerAuthenticator(imap4.LOGINAuthenticator(self.username)) 
     92        p.registerAuthenticator( 
     93                imap4.CramMD5ClientAuthenticator(self.username)) 
     94 
    7495        return p 
    7596     
     97 
    7698    def clientConnectionFailed(self, connector, reason): 
    7799        d, self.onConn = self.onConn, None 
    78100        d.errback(reason) 
    79101 
    80 # Initial callback - invoked after the server sends us its greet message 
     102 
     103 
    81104def cbServerGreeting(proto, username, password): 
     105    """ 
     106    Initial callback - invoked after the server sends us its greet message. 
     107    """ 
    82108    # Hook up stdio 
    83109    tp = TrivialPrompter() 
    84110    stdio.StandardIO(tp) 
     
    93119        ).addErrback(ebAuthentication, proto, username, password 
    94120        ) 
    95121 
    96 # Fallback error-handler.  If anything goes wrong, log it and quit. 
     122 
    97123def ebConnection(reason): 
     124    """ 
     125    Fallback error-handler. If anything goes wrong, log it and quit. 
     126    """ 
    98127    log.startLogging(sys.stdout) 
    99128    log.err(reason) 
    100     from twisted.internet import reactor 
    101     reactor.stop() 
     129    return reason 
    102130 
    103 # Callback after authentication has succeeded 
     131 
    104132def cbAuthentication(result, proto): 
    105     # List a bunch of mailboxes 
     133    """ 
     134    Callback after authentication has succeeded. 
     135    List a bunch of mailboxes. 
     136    """ 
    106137    return proto.list("", "*" 
    107138        ).addCallback(cbMailboxList, proto 
    108139        ) 
    109140 
    110 # Errback invoked when authentication fails 
     141 
    111142def ebAuthentication(failure, proto, username, password): 
    112     # If it failed because no SASL mechanisms match, offer the user the choice 
    113     # of logging in insecurely. 
     143    """ 
     144    Errback invoked when authentication fails. 
     145    If it failed because no SASL mechanisms match, offer the user the choice 
     146    of logging in insecurely. 
     147    If you are trying to connect to your Gmail account, you will be here! 
     148    """ 
    114149    failure.trap(imap4.NoSupportedAuthentication) 
    115     return proto.prompt("No secure authentication available.  Login insecurely? (y/N) " 
     150    return proto.prompt( 
     151        "No secure authentication available. Login insecurely? (y/N) " 
    116152        ).addCallback(cbInsecureLogin, proto, username, password 
    117153        ) 
    118154 
    119 # Callback for "insecure-login" prompt 
     155 
    120156def cbInsecureLogin(result, proto, username, password): 
     157    """ 
     158    Callback for "insecure-login" prompt. 
     159    """ 
    121160    if result.lower() == "y": 
    122161        # If they said yes, do it. 
    123162        return proto.login(username, password 
     
    125164            ) 
    126165    return defer.fail(Exception("Login failed for security reasons.")) 
    127166 
    128 # Callback invoked when a list of mailboxes has been retrieved 
     167 
    129168def cbMailboxList(result, proto): 
     169    """ 
     170    Callback invoked when a list of mailboxes has been retrieved. 
     171    """ 
    130172    result = [e[2] for e in result] 
    131173    s = '\n'.join(['%d. %s' % (n + 1, m) for (n, m) in zip(range(len(result)), result)]) 
    132174    if not s: 
     
    135177        ).addCallback(cbPickMailbox, proto, result 
    136178        ) 
    137179 
    138 # When the user selects a mailbox, "examine" it. 
     180 
    139181def cbPickMailbox(result, proto, mboxes): 
     182    """ 
     183    When the user selects a mailbox, "examine" it. 
     184    """ 
    140185    mbox = mboxes[int(result or '1') - 1] 
    141186    return proto.examine(mbox 
    142187        ).addCallback(cbExamineMbox, proto 
    143188        ) 
    144189 
    145 # Callback invoked when examine command completes. 
     190 
    146191def cbExamineMbox(result, proto): 
    147     # Retrieve the subject header of every message on the mailbox. 
     192    """ 
     193    Callback invoked when examine command completes. 
     194    Retrieve the subject header of every message on the mailbox. 
     195    """ 
    148196    return proto.fetchSpecific('1:*', 
    149197                               headerType='HEADER.FIELDS', 
    150                                headerArgs=['SUBJECT'] 
     198                               headerArgs=['SUBJECT'], 
    151199        ).addCallback(cbFetch, proto 
    152200        ) 
    153201 
    154 # Finally, display headers. 
     202 
    155203def cbFetch(result, proto): 
    156     keys = result.keys() 
    157     keys.sort() 
    158     for k in keys: 
    159         proto.display('%s %s' % (k, result[k][0][2])) 
     204    """ 
     205    Finally, display headers. 
     206    """ 
     207    if result: 
     208        keys = result.keys() 
     209        keys.sort() 
     210        for k in keys: 
     211            proto.display('%s %s' % (k, result[k][0][2])) 
     212    else: 
     213        print "Hey, an empty mailbox!" 
     214 
    160215    return proto.logout() 
    161216 
    162 PORT = 143 
    163217 
     218def cbClose(result): 
     219    """ 
     220    Close the connection when we finish everything. 
     221    """ 
     222    from twisted.internet import reactor 
     223    reactor.stop() 
     224 
     225 
    164226def main(): 
    165227    hostname = raw_input('IMAP4 Server Hostname: ') 
     228    port = raw_input('IMAP4 Server Port (the default is 143): ') 
    166229    username = raw_input('IMAP4 Username: ') 
    167230    password = util.getPassword('IMAP4 Password: ') 
    168231     
    169232    onConn = defer.Deferred( 
    170233        ).addCallback(cbServerGreeting, username, password 
    171234        ).addErrback(ebConnection 
    172         ) 
     235        ).addBoth(cbClose) 
    173236 
    174237    factory = SimpleIMAP4ClientFactory(username, onConn) 
    175238     
    176239    from twisted.internet import reactor 
    177     conn = reactor.connectTCP(hostname, PORT, factory) 
     240    if port == '993': 
     241        conn = reactor.connectSSL(hostname, int(port), factory, ssl.ClientContextFactory()) 
     242    else: 
     243        if not port: 
     244            port = 143 
     245        conn = reactor.connectTCP(hostname, int(port), factory) 
    178246    reactor.run() 
    179247 
     248 
    180249if __name__ == '__main__': 
    181250    main()