License New BSD license
Lines 116
Keywords
email (2) pop (1) server (3) twisted (1)
Permissions
Viewable by Everyone
Editable by All Siafoo Users
Hide
Need a quick chart or graph for your blog? Try our reStructured Text renderer. Join Siafoo Now or Learn More

Twisted POP Server Atom Feed 0

In Brief Runs a POP server using the twisted framework.... more
# 's
  1# Copyright (c) 2010 David Isaacson <david@icapsid.net>
2# Portions from 'twimapd' copyright (c) 2010 Dav Glass <davglass@gmail.com>
3# New BSD License
4
5import StringIO
6from md5 import md5
7from twisted.cred import checkers, credentials, portal
8from twisted.cred.error import
9from twisted.internet import defer, reactor, protocol
10from twisted.mail import pop3
11from zope.interface import implements
12
13from somewhere import authenticate, get_messages
14
15class WallMailbox(object):
16 ''' an avatar representing a per-user mailbox '''
17
18 implements(pop3.IMailbox)
19
20 def __init__(self,id,cache):
21 #self.msgs = ['this is a very basic test for id ' + id]
22 # Load Messages!
23 self.msgs = [message.encode('utf-8', 'replace') for message in get_messages(id, cache)]
24 self.cache = cache
25
26 def listMessages(self, i=None):
27 if i is None:
28 return [self.listMessages(i) for i in range(len(self.msgs))]
29 elif i >= len(self.msgs):
30 raise ValueError
31 return len(self.msgs[i])
32
33 def getMessage(self, i):
34 if i >= len(self.msgs):
35 raise ValueError
36 return StringIO.StringIO(self.msgs[i])
37
38 def getUidl(self, i):
39 if i >= len(self.msgs):
40 raise ValueError
41 return md5(self.msgs[i]).hexdigest()
42
43 def deleteMessage(self):
44 pass
45
46 def undeleteMessage(self):
47 pass
48
49 def sync(self):
50 pass
51
52class WallCredentialsChecker(object):
53
54 ''' authentication: given credentials, returns an avatar id (a reference to a
55 particular user and possibly their mailbox)'''
56
57 implements(checkers.ICredentialsChecker)
58 credentialInterfaces = (credentials.IUsernamePassword,)
59
60 def __init__(self, cache):
61 self.cache = cache
62
63 def requestAvatarId(self, creds):
64 # do authentication here with creds.username, creds.password
65 user_id = authenticate(creds.username, creds.password)
66 if not user_id:
67 return defer.fail(UnauthorizedLogin("Bad username or password"))
68 return defer.succeed(user_id)
69
70class WallUserRealm(object):
71 ''' given an interface (type of avatar) and an avatar id (a reference to a user),
72 returns the correct sort of avatar for the correct user'''
73
74 implements(portal.IRealm)
75 avatarInterfaces = {
76 pop3.IMailbox: WallMailbox,
77 }
78
79 def __init__(self, cache):
80 self.cache = cache
81
82 def requestAvatar(self, avatarId, mind, *interfaces):
83 for requestedInterface in interfaces:
84 if self.avatarInterfaces.has_key(requestedInterface):
85 # return an instance of the correct class
86 avatarClass = self.avatarInterfaces[requestedInterface]
87 avatar = avatarClass(avatarId, self.cache)
88 # null logout function: take no arguments and do nothing
89 logout = lambda: None
90 return defer.succeed((requestedInterface, avatar, logout))
91
92 # none of the requested interfaces was supported
93 raise KeyError("None of the requested interfaces is supported")
94
95
96class POP3Debug(pop3.POP3):
97 ''' the server '''
98
99 def connectionMade(self):
100 print "Connection Made"
101 return pop3.POP3.connectionMade(self)
102
103
104class POP3Factory(protocol.Factory):
105 ''' creates and initializes the server '''
106
107 protocol = POP3Debug
108 portal = None # placeholder
109
110 def buildProtocol(self, address):
111 p = self.protocol()
112 p.portal = self.portal
113 p.factory = self
114 return p
115
116class ObjCache(object):
117 def __init__(self):
118 self.cache = {}
119
120 def get(self, item):
121 return self.cache[item]
122
123 def set(self, item, value):
124 self.cache[item] = value
125
126
127if __name__ == "__main__":
128
129 cache = ObjCache() #just a simple way to have 'global' variables for now
130
131 portal = portal.Portal(WallUserRealm(cache))
132 portal.registerChecker(WallCredentialsChecker(cache))
133
134 factory = POP3Factory()
135 factory.portal = portal
136
137 reactor.listenTCP(1110, factory)
138 reactor.run()

Runs a POP server using the twisted framework.

The reactor starts a factory at a given port. The factory initializes the actual base server, which is provided by twisted and subclassed here for debugging. The base server is provided a realm and a credentials checker via the portal. The credentials checker here accepts username and password, and returns a user_id via the function somewhere.authenticate. The realm is given the user_id (or whatever the credentials checker returns) and the type of interface (avatar) that the server is looking for (here a mailbox) and initializes and returns a per-user mailbox. The mailbox then returns the messages, an array provided by somewhere.get_messages in this example.

For more information check out http://twistedmatrix.com/documents/current/core/howto/cred.html

Comments

over 6 years ago (15 Jan 2010 at 04:25 PM) by David Isaacson
Happy stou? : )
over 6 years ago (16 Jan 2010 at 02:38 PM) by Stou S.
Yes, I am ecstatic