root / trunk / twisted / mail / tap.py

Revision 25168, 6.7 kB (checked in by exarkun, 8 months ago)

Merge remove-mktap-3393

Author: kehander1, exarkun
Reviewer: ralphm, itamar
Fixes: #3393

Remove almost all references to mktap(1) from the Twisted documentation.

The finger tutorial still refers to mktap since it also contains an
old-style plugin which will not work with twistd.

Line 
1 # -*- test-case-name: twisted.mail.test.test_options -*-
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5
6 """I am the support module for creating mail servers with twistd
7 """
8
9 import os
10 import sys
11
12 from twisted.mail import mail
13 from twisted.mail import maildir
14 from twisted.mail import relay
15 from twisted.mail import relaymanager
16 from twisted.mail import alias
17
18 from twisted.python import usage
19
20 from twisted.cred import checkers
21 from twisted.application import internet
22
23
24 class Options(usage.Options):
25     synopsis = "[options]"
26
27     optParameters = [
28         ["pop3", "p", 8110, "Port to start the POP3 server on (0 to disable).", usage.portCoerce],
29         ["pop3s", "S", 0, "Port to start the POP3-over-SSL server on (0 to disable).", usage.portCoerce],
30         ["smtp", "s", 8025, "Port to start the SMTP server on (0 to disable).", usage.portCoerce],
31         ["certificate", "c", None, "Certificate file to use for SSL connections"],
32         ["relay", "R", None,
33             "Relay messages according to their envelope 'To', using the given"
34             "path as a queue directory."],
35         ["hostname", "H", None, "The hostname by which to identify this server."],
36     ]
37
38     optFlags = [
39         ["esmtp", "E", "Use RFC 1425/1869 SMTP extensions"],
40         ["disable-anonymous", None, "Disallow non-authenticated SMTP connections"],
41     ]
42     zsh_actions = {"hostname" : "_hosts"}
43
44     longdesc = "This creates a mail.tap file that can be used by twistd."
45
46     def __init__(self):
47         usage.Options.__init__(self)
48         self.service = mail.MailService()
49         self.last_domain = None
50
51     def opt_passwordfile(self, filename):
52         """Specify a file containing username:password login info for authenticated ESMTP connections."""
53         ch = checkers.OnDiskUsernamePasswordDatabase(filename)
54         self.service.smtpPortal.registerChecker(ch)
55     opt_P = opt_passwordfile
56
57     def opt_default(self):
58         """Make the most recently specified domain the default domain."""
59         if self.last_domain:
60             self.service.addDomain('', self.last_domain)
61         else:
62             raise usage.UsageError("Specify a domain before specifying using --default")
63     opt_D = opt_default
64
65     def opt_maildirdbmdomain(self, domain):
66         """generate an SMTP/POP3 virtual domain which saves to \"path\"
67         """
68         try:
69             name, path = domain.split('=')
70         except ValueError:
71             raise usage.UsageError("Argument to --maildirdbmdomain must be of the form 'name=path'")
72
73         self.last_domain = maildir.MaildirDirdbmDomain(self.service, os.path.abspath(path))
74         self.service.addDomain(name, self.last_domain)
75     opt_d = opt_maildirdbmdomain
76
77     def opt_user(self, user_pass):
78         """add a user/password to the last specified domains
79         """
80         try:
81             user, password = user_pass.split('=', 1)
82         except ValueError:
83             raise usage.UsageError("Argument to --user must be of the form 'user=password'")
84         if self.last_domain:
85             self.last_domain.addUser(user, password)
86         else:
87             raise usage.UsageError("Specify a domain before specifying users")
88     opt_u = opt_user
89
90     def opt_bounce_to_postmaster(self):
91         """undelivered mails are sent to the postmaster
92         """
93         self.last_domain.postmaster = 1
94     opt_b = opt_bounce_to_postmaster
95
96     def opt_aliases(self, filename):
97         """Specify an aliases(5) file to use for this domain"""
98         if self.last_domain is not None:
99             if mail.IAliasableDomain.providedBy(self.last_domain):
100                 aliases = alias.loadAliasFile(self.service.domains, filename)
101                 self.last_domain.setAliasGroup(aliases)
102                 self.service.monitor.monitorFile(
103                     filename,
104                     AliasUpdater(self.service.domains, self.last_domain)
105                 )
106             else:
107                 raise usage.UsageError(
108                     "%s does not support alias files" % (
109                         self.last_domain.__class__.__name__,
110                     )
111                 )
112         else:
113             raise usage.UsageError("Specify a domain before specifying aliases")
114     opt_A = opt_aliases
115
116     def postOptions(self):
117         if self['pop3s']:
118             if not self['certificate']:
119                 raise usage.UsageError("Cannot specify --pop3s without "
120                                        "--certificate")
121             elif not os.path.exists(self['certificate']):
122                 raise usage.UsageError("Certificate file %r does not exist."
123                                        % self['certificate'])
124
125         if not self['disable-anonymous']:
126             self.service.smtpPortal.registerChecker(checkers.AllowAnonymousAccess())
127
128         if not (self['pop3'] or self['smtp'] or self['pop3s']):
129             raise usage.UsageError("You cannot disable all protocols")
130
131 class AliasUpdater:
132     def __init__(self, domains, domain):
133         self.domains = domains
134         self.domain = domain
135     def __call__(self, new):
136         self.domain.setAliasGroup(alias.loadAliasFile(self.domains, new))
137
138 def makeService(config):
139     if config['esmtp']:
140         rmType = relaymanager.SmartHostESMTPRelayingManager
141         smtpFactory = config.service.getESMTPFactory
142     else:
143         rmType = relaymanager.SmartHostSMTPRelayingManager
144         smtpFactory = config.service.getSMTPFactory
145
146     if config['relay']:
147         dir = config['relay']
148         if not os.path.isdir(dir):
149             os.mkdir(dir)
150
151         config.service.setQueue(relaymanager.Queue(dir))
152         default = relay.DomainQueuer(config.service)
153
154         manager = rmType(config.service.queue)
155         if config['esmtp']:
156             manager.fArgs += (None, None)
157         manager.fArgs += (config['hostname'],)
158
159         helper = relaymanager.RelayStateHelper(manager, 1)
160         helper.setServiceParent(config.service)
161         config.service.domains.setDefaultDomain(default)
162
163     ctx = None
164     if config['certificate']:
165         from twisted.mail.protocols import SSLContextFactory
166         ctx = SSLContextFactory(config['certificate'])
167
168     if config['pop3']:
169         s = internet.TCPServer(config['pop3'], config.service.getPOP3Factory())
170         s.setServiceParent(config.service)
171     if config['pop3s']:
172         s = internet.SSLServer(config['pop3s'],
173                                config.service.getPOP3Factory(), ctx)
174         s.setServiceParent(config.service)
175     if config['smtp']:
176         f = smtpFactory()
177         f.context = ctx
178         if config['hostname']:
179             f.domain = config['hostname']
180             f.fArgs = (f.domain,)
181         if config['esmtp']:
182             f.fArgs = (None, None) + f.fArgs
183         s = internet.TCPServer(config['smtp'], f)
184         s.setServiceParent(config.service)
185     return config.service
Note: See TracBrowser for help on using the browser.