text: # -*- test-case-name: twisted.mail.test.test_options -*-
  # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
  # See LICENSE for details.
  
  
  """I am the support module for creating mail servers with 'mktap'
  """
  
  import os
  import sys
  
  from twisted.mail import mail
  from twisted.mail import maildir
  from twisted.mail import relay
  from twisted.mail import relaymanager
  from twisted.mail import alias
  
  from twisted.python import usage
  
  from twisted.cred import checkers
  from twisted.application import internet
  
  
  class Options(usage.Options):
      synopsis = "Usage: mktap mail [options]"
  
      optParameters = [
          ["pop3", "p", 8110, "Port to start the POP3 server on (0 to disable)."],
          ["pop3s", "S", 0, "Port to start the POP3-over-SSL server on (0 to disable)."],
          ["smtp", "s", 8025, "Port to start the SMTP server on (0 to disable)."],
          ["certificate", "c", None, "Certificate file to use for SSL connections"],
          ["relay", "R", None,
              "Relay messages according to their envelope 'To', using the given"
              "path as a queue directory."],
          ["hostname", "H", None, "The hostname by which to identify this server."],
      ]
  
      optFlags = [
          ["esmtp", "E", "Use RFC 1425/1869 SMTP extensions"],
          ["disable-anonymous", None, "Disallow non-authenticated SMTP connections"],
      ]
      zsh_actions = {"hostname" : "_hosts"}
  
      longdesc = "This creates a mail.tap file that can be used by twistd."
  
      def __init__(self):
          usage.Options.__init__(self)
          self.service = mail.MailService()
          self.last_domain = None
  
      def opt_passwordfile(self, filename):
          """Specify a file containing username:password login info for authenticated ESMTP connections."""
          ch = checkers.OnDiskUsernamePasswordDatabase(filename)
          self.service.smtpPortal.registerChecker(ch)
      opt_P = opt_passwordfile
  
      def opt_default(self):
          """Make the most recently specified domain the default domain."""
          if self.last_domain:
              self.service.addDomain('', self.last_domain)
          else:
              raise usage.UsageError("Specify a domain before specifying using --default")
      opt_D = opt_default
  
      def opt_maildirdbmdomain(self, domain):
          """generate an SMTP/POP3 virtual domain which saves to \"path\"
          """
          try:
              name, path = domain.split('=')
          except ValueError:
              raise usage.UsageError("Argument to --maildirdbmdomain must be of the form 'name=path'")
  
          self.last_domain = maildir.MaildirDirdbmDomain(self.service, os.path.abspath(path))
          self.service.addDomain(name, self.last_domain)
      opt_d = opt_maildirdbmdomain
  
      def opt_user(self, user_pass):
          """add a user/password to the last specified domains
          """
          try:
              user, password = user_pass.split('=', 1)
          except ValueError:
              raise usage.UsageError("Argument to --user must be of the form 'user=password'")
          if self.last_domain:
              self.last_domain.addUser(user, password)
          else:
              raise usage.UsageError("Specify a domain before specifying users")
      opt_u = opt_user
  
      def opt_bounce_to_postmaster(self):
          """undelivered mails are sent to the postmaster
          """
          self.last_domain.postmaster = 1
      opt_b = opt_bounce_to_postmaster
  
      def opt_aliases(self, filename):
          """Specify an aliases(5) file to use for this domain"""
          if self.last_domain is not None:
              if mail.IAliasableDomain.providedBy(self.last_domain):
                  aliases = alias.loadAliasFile(self.service.domains, filename)
                  self.last_domain.setAliasGroup(aliases)
                  self.service.monitor.monitorFile(
                      filename,
                      AliasUpdater(self.service.domains, self.last_domain)
                  )
              else:
                  raise usage.UsageError(
                      "%s does not support alias files" % (
                          self.last_domain.__class__.__name__,
                      )
                  )
          else:
              raise usage.UsageError("Specify a domain before specifying aliases")
      opt_A = opt_aliases
  
      def postOptions(self):
          for f in ('pop3', 'smtp', 'pop3s'):
              try:
                  self[f] = int(self[f])
                  if not (0 <= self[f] < 2 ** 16):
                      raise ValueError
              except ValueError:
                  raise usage.UsageError(
                      'Invalid port specified to --%s: %s' % (f, self[f])
                  )
          if self['pop3s']:
              if not self['certificate']:
                  raise usage.UsageError("Cannot specify --pop3s without "
                                         "--certificate")
              elif not os.path.exists(self['certificate']):
                  raise usage.UsageError("Certificate file %r does not exist."
                                         % self['certificate'])
  
          if not self['disable-anonymous']:
              self.service.smtpPortal.registerChecker(checkers.AllowAnonymousAccess())
  
          if not (self['pop3'] or self['smtp'] or self['pop3s']):
              raise usage.UsageError("You cannot disable all protocols")
  
  class AliasUpdater:
      def __init__(self, domains, domain):
          self.domains = domains
          self.domain = domain
      def __call__(self, new):
          self.domain.setAliasGroup(alias.loadAliasFile(self.domains, new))
  
  def makeService(config):
      if config['esmtp']:
          rmType = relaymanager.SmartHostESMTPRelayingManager
          smtpFactory = config.service.getESMTPFactory
      else:
          rmType = relaymanager.SmartHostSMTPRelayingManager
          smtpFactory = config.service.getSMTPFactory
  
      if config['relay']:
          dir = config['relay']
          if not os.path.isdir(dir):
              os.mkdir(dir)
  
          config.service.setQueue(relaymanager.Queue(dir))
          default = relay.DomainQueuer(config.service)
  
          manager = rmType(config.service.queue)
          if config['esmtp']:
              manager.fArgs += (None, None)
          manager.fArgs += (config['hostname'],)
  
          helper = relaymanager.RelayStateHelper(manager, 1)
          helper.setServiceParent(config.service)
          config.service.domains.setDefaultDomain(default)
  
      ctx = None
      if config['certificate']:
          from twisted.mail.protocols import SSLContextFactory
          ctx = SSLContextFactory(config['certificate'])
  
      if config['pop3']:
          s = internet.TCPServer(config['pop3'], config.service.getPOP3Factory())
          s.setServiceParent(config.service)
      if config['pop3s']:
          s = internet.SSLServer(config['pop3s'],
                                 config.service.getPOP3Factory(), ctx)
          s.setServiceParent(config.service)
      if config['smtp']:
          f = smtpFactory()
          f.context = ctx
          if config['hostname']:
              f.domain = config['hostname']
              f.fArgs = (f.domain,)
          if config['esmtp']:
              f.fArgs = (None, None) + f.fArgs
          s = internet.TCPServer(config['smtp'], f)
          s.setServiceParent(config.service)
      return config.service
  