~0x44/nova/extdoc

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/doc/mail/examples/imap4client.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
 
4
# See LICENSE for details.
 
5
 
 
6
 
 
7
"""
 
8
Simple IMAP4 client which displays the subjects of all messages in a 
 
9
particular mailbox.
 
10
"""
 
11
 
 
12
import sys
 
13
 
 
14
from twisted.internet import protocol
 
15
from twisted.internet import ssl
 
16
from twisted.internet import defer
 
17
from twisted.internet import stdio
 
18
from twisted.mail import imap4
 
19
from twisted.protocols import basic
 
20
from twisted.python import util
 
21
from twisted.python import log
 
22
 
 
23
class TrivialPrompter(basic.LineReceiver):
 
24
    from os import linesep as delimiter
 
25
 
 
26
    promptDeferred = None
 
27
    
 
28
    def prompt(self, msg):
 
29
        assert self.promptDeferred is None
 
30
        self.display(msg)
 
31
        self.promptDeferred = defer.Deferred()
 
32
        return self.promptDeferred
 
33
    
 
34
    def display(self, msg):
 
35
        self.transport.write(msg)
 
36
    
 
37
    def lineReceived(self, line):    
 
38
        if self.promptDeferred is None:
 
39
            return
 
40
        d, self.promptDeferred = self.promptDeferred, None
 
41
        d.callback(line)
 
42
 
 
43
class SimpleIMAP4Client(imap4.IMAP4Client):
 
44
    greetDeferred = None
 
45
    
 
46
    def serverGreeting(self, caps):
 
47
        self.serverCapabilities = caps
 
48
        if self.greetDeferred is not None:
 
49
            d, self.greetDeferred = self.greetDeferred, None
 
50
            d.callback(self)
 
51
 
 
52
class SimpleIMAP4ClientFactory(protocol.ClientFactory):
 
53
    usedUp = False
 
54
 
 
55
    protocol = SimpleIMAP4Client
 
56
 
 
57
    def __init__(self, username, onConn):
 
58
        self.ctx = ssl.ClientContextFactory()
 
59
        
 
60
        self.username = username
 
61
        self.onConn = onConn
 
62
 
 
63
    def buildProtocol(self, addr):
 
64
        assert not self.usedUp
 
65
        self.usedUp = True
 
66
        
 
67
        p = self.protocol(self.ctx)
 
68
        p.factory = self
 
69
        p.greetDeferred = self.onConn
 
70
 
 
71
        auth = imap4.CramMD5ClientAuthenticator(self.username)
 
72
        p.registerAuthenticator(auth)
 
73
        
 
74
        return p
 
75
    
 
76
    def clientConnectionFailed(self, connector, reason):
 
77
        d, self.onConn = self.onConn, None
 
78
        d.errback(reason)
 
79
 
 
80
# Initial callback - invoked after the server sends us its greet message
 
81
def cbServerGreeting(proto, username, password):
 
82
    # Hook up stdio
 
83
    tp = TrivialPrompter()
 
84
    stdio.StandardIO(tp)
 
85
    
 
86
    # And make it easily accessible
 
87
    proto.prompt = tp.prompt
 
88
    proto.display = tp.display
 
89
 
 
90
    # Try to authenticate securely
 
91
    return proto.authenticate(password
 
92
        ).addCallback(cbAuthentication, proto
 
93
        ).addErrback(ebAuthentication, proto, username, password
 
94
        )
 
95
 
 
96
# Fallback error-handler.  If anything goes wrong, log it and quit.
 
97
def ebConnection(reason):
 
98
    log.startLogging(sys.stdout)
 
99
    log.err(reason)
 
100
    from twisted.internet import reactor
 
101
    reactor.stop()
 
102
 
 
103
# Callback after authentication has succeeded
 
104
def cbAuthentication(result, proto):
 
105
    # List a bunch of mailboxes
 
106
    return proto.list("", "*"
 
107
        ).addCallback(cbMailboxList, proto
 
108
        )
 
109
 
 
110
# Errback invoked when authentication fails
 
111
def ebAuthentication(failure, proto, username, password):
 
112
    # If it failed because no SASL mechanisms match, offer the user the choice
 
113
    # of logging in insecurely.
 
114
    failure.trap(imap4.NoSupportedAuthentication)
 
115
    return proto.prompt("No secure authentication available.  Login insecurely? (y/N) "
 
116
        ).addCallback(cbInsecureLogin, proto, username, password
 
117
        )
 
118
 
 
119
# Callback for "insecure-login" prompt
 
120
def cbInsecureLogin(result, proto, username, password):
 
121
    if result.lower() == "y":
 
122
        # If they said yes, do it.
 
123
        return proto.login(username, password
 
124
            ).addCallback(cbAuthentication, proto
 
125
            )
 
126
    return defer.fail(Exception("Login failed for security reasons."))
 
127
 
 
128
# Callback invoked when a list of mailboxes has been retrieved
 
129
def cbMailboxList(result, proto):
 
130
    result = [e[2] for e in result]
 
131
    s = '\n'.join(['%d. %s' % (n + 1, m) for (n, m) in zip(range(len(result)), result)])
 
132
    if not s:
 
133
        return defer.fail(Exception("No mailboxes exist on server!"))
 
134
    return proto.prompt(s + "\nWhich mailbox? [1] "
 
135
        ).addCallback(cbPickMailbox, proto, result
 
136
        )
 
137
 
 
138
# When the user selects a mailbox, "examine" it.
 
139
def cbPickMailbox(result, proto, mboxes):
 
140
    mbox = mboxes[int(result or '1') - 1]
 
141
    return proto.examine(mbox
 
142
        ).addCallback(cbExamineMbox, proto
 
143
        )
 
144
 
 
145
# Callback invoked when examine command completes.
 
146
def cbExamineMbox(result, proto):
 
147
    # Retrieve the subject header of every message on the mailbox.
 
148
    return proto.fetchSpecific('1:*',
 
149
                               headerType='HEADER.FIELDS',
 
150
                               headerArgs=['SUBJECT']
 
151
        ).addCallback(cbFetch, proto
 
152
        )
 
153
 
 
154
# Finally, display headers.
 
155
def 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]))
 
160
    return proto.logout()
 
161
 
 
162
PORT = 143
 
163
 
 
164
def main():
 
165
    hostname = raw_input('IMAP4 Server Hostname: ')
 
166
    username = raw_input('IMAP4 Username: ')
 
167
    password = util.getPassword('IMAP4 Password: ')
 
168
    
 
169
    onConn = defer.Deferred(
 
170
        ).addCallback(cbServerGreeting, username, password
 
171
        ).addErrback(ebConnection
 
172
        )
 
173
 
 
174
    factory = SimpleIMAP4ClientFactory(username, onConn)
 
175
    
 
176
    from twisted.internet import reactor
 
177
    conn = reactor.connectTCP(hostname, PORT, factory)
 
178
    reactor.run()
 
179
 
 
180
if __name__ == '__main__':
 
181
    main()