# HG changeset patch # User masklinn # Date 1298219353 -3600 # Branch py3k # Node ID 55cbf2aa98b498d52e3de97ae6961d44ceb51eb3 # Parent 02b70cb597012cf7a46ddd0209af331f72aaaaa3 Remove form feeds (0xC) from smtpd.py diff --git a/Lib/smtpd.py b/Lib/smtpd.py --- a/Lib/smtpd.py +++ b/Lib/smtpd.py @@ -1,41 +1,5 @@ #! /usr/bin/env python3 -"""An RFC 2821 smtp proxy. -Usage: %(program)s [options] [localhost:localport [remotehost:remoteport]] - -Options: - - --nosetuid - -n - This program generally tries to setuid `nobody', unless this flag is - set. The setuid call will fail if this program is not run as root (in - which case, use this flag). - - --version - -V - Print the version number and exit. - - --class classname - -c classname - Use `classname' as the concrete SMTP proxy class. Uses `PureProxy' by - default. - - --debug - -d - Turn on debugging prints. - - --help - -h - Print this message and exit. - -Version: %(__version__)s - -If localhost is not given then `localhost' is used, and if localport is not -given then 8025 is used. If remotehost is not given then `localhost' is used, -and if remoteport is not given, then 25 is used. -""" - - # Overview: # # This file implements the minimal SMTP protocol as defined in RFC 821. It @@ -69,10 +33,10 @@ # - ESMTP # - handle error codes from the backend smtpd +import argparse import sys import os import errno -import getopt import time import socket import asyncore @@ -96,15 +60,6 @@ COMMASPACE = ', ' - -def usage(code, msg=''): - print(__doc__ % globals(), file=sys.stderr) - if msg: - print(msg, file=sys.stderr) - sys.exit(code) - - - class SMTPChannel(asynchat.async_chat): COMMAND = 0 DATA = 1 @@ -422,7 +377,6 @@ self.push('354 End data with .') - class SMTPServer(asyncore.dispatcher): # SMTPChannel class to use for managing client connections channel_class = SMTPChannel @@ -475,7 +429,6 @@ raise NotImplementedError - class DebuggingServer(SMTPServer): # Do something with the gathered message def process_message(self, peer, mailfrom, rcpttos, data): @@ -491,7 +444,6 @@ print('------------ END MESSAGE ------------') - class PureProxy(SMTPServer): def process_message(self, peer, mailfrom, rcpttos, data): lines = data.split('\n') @@ -532,7 +484,7 @@ return refused - + class MailmanProxy(PureProxy): def process_message(self, peer, mailfrom, rcpttos, data): from io import StringIO @@ -611,70 +563,61 @@ msg.Enqueue(mlist, torequest=1) - -class Options: - setuid = 1 - classname = 'PureProxy' +def SpecType(value): + i = value.find(':') + if i < 0: + raise argparse.ArgumentTypeError('bad spec: %s' % value) + try: + port = int(value[i+1:]) + except ValueError: + raise argparse.ArgumentTypeError('bad port: %s' % value[i+1:]) + return (value[:i], port) +class SpecAction(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + delattr(namespace, self.dest) + host, port = values + setattr(namespace, '{}host'.format(self.dest), host) + setattr(namespace, '{}port'.format(self.dest), port) - +class DebugAction(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + global DEBUGSTREAM + DEBUGSTREAM = sys.stderr + def parseargs(): - global DEBUGSTREAM - try: - opts, args = getopt.getopt( - sys.argv[1:], 'nVhc:d', - ['class=', 'nosetuid', 'version', 'help', 'debug']) - except getopt.error as e: - usage(1, e) + parser = argparse.ArgumentParser(description="An RFC 2821 smtp proxy.") + parser.add_argument('-n', '--nosetuid', dest='setuid', + action="store_false", default=True, + help="this program generally tries to setuid `nobody', " + "unless this flag is set. The setuid call will fail if " + "this program is not run as root (in which case, use " + "this flag).") + parser.add_argument('-V', '--version', action='version', + version=__version__, + help="show the version number and exit.") + parser.add_argument('-c', '--class', metavar='classname', + dest='classname', default='PureProxy', + help="use `classname' as the concrete SMTP proxy class." + " `classname' can be a dotted name to use third-party " + "proxy classes (not part of `smtpd'). Defaults to " + "`PureProxy'.") + parser.add_argument('-d', '--debug', dest='debug', nargs=0, + action=DebugAction, help='turn on debugging prints.') - options = Options() - for opt, arg in opts: - if opt in ('-h', '--help'): - usage(0) - elif opt in ('-V', '--version'): - print(__version__, file=sys.stderr) - sys.exit(0) - elif opt in ('-n', '--nosetuid'): - options.setuid = 0 - elif opt in ('-c', '--class'): - options.classname = arg - elif opt in ('-d', '--debug'): - DEBUGSTREAM = sys.stderr + parser.add_argument('local', nargs='?', action=SpecAction, type=SpecType, + default='localhost:8025', + metavar='localhost:localport', + help="localhost defaults to `localhost' and localport " + "defaults to `8025' if they are not provided") + parser.add_argument('remote', nargs='?', action=SpecAction, type=SpecType, + default='localhost:25', + metavar='remotehost:remotespec', + help="remotehost defaults to `localhost' and " + "remoteport defaults to `25' if they are not provided") + return parser.parse_args() - # parse the rest of the arguments - if len(args) < 1: - localspec = 'localhost:8025' - remotespec = 'localhost:25' - elif len(args) < 2: - localspec = args[0] - remotespec = 'localhost:25' - elif len(args) < 3: - localspec = args[0] - remotespec = args[1] - else: - usage(1, 'Invalid arguments: %s' % COMMASPACE.join(args)) - # split into host/port pairs - i = localspec.find(':') - if i < 0: - usage(1, 'Bad local spec: %s' % localspec) - options.localhost = localspec[:i] - try: - options.localport = int(localspec[i+1:]) - except ValueError: - usage(1, 'Bad local port: %s' % localspec) - i = remotespec.find(':') - if i < 0: - usage(1, 'Bad remote spec: %s' % remotespec) - options.remotehost = remotespec[:i] - try: - options.remoteport = int(remotespec[i+1:]) - except ValueError: - usage(1, 'Bad remote port: %s' % remotespec) - return options - - - if __name__ == '__main__': options = parseargs() # Become nobody