X-FTP
[x93.git/.git] / xftp.git / ext / pyftpdlib / __main__.py
1 # Copyright (C) 2007 Giampaolo Rodola' <g.rodola@gmail.com>.\r
2 # Use of this source code is governed by MIT license that can be\r
3 # found in the LICENSE file.\r
4 \r
5 """\r
6 Start a stand alone anonymous FTP server from the command line as in:\r
7 \r
8 $ python -m pyftpdlib\r
9 """\r
10 \r
11 import logging\r
12 import optparse\r
13 import os\r
14 import sys\r
15 \r
16 from . import __ver__\r
17 from ._compat import getcwdu\r
18 from .authorizers import DummyAuthorizer\r
19 from .handlers import FTPHandler\r
20 from .log import config_logging\r
21 from .servers import FTPServer\r
22 \r
23 \r
24 class CustomizedOptionFormatter(optparse.IndentedHelpFormatter):\r
25     """Formats options shown in help in a prettier way."""\r
26 \r
27     def format_option(self, option):\r
28         result = []\r
29         opts = self.option_strings[option]\r
30         result.append('  %s\n' % opts)\r
31         if option.help:\r
32             help_text = '     %s\n\n' % self.expand_default(option)\r
33             result.append(help_text)\r
34         return ''.join(result)\r
35 \r
36 \r
37 def main():\r
38     """Start a stand alone anonymous FTP server."""\r
39     usage = "python -m pyftpdlib [options]"\r
40     parser = optparse.OptionParser(usage=usage, description=main.__doc__,\r
41                                    formatter=CustomizedOptionFormatter())\r
42     parser.add_option('-i', '--interface', default=None, metavar="ADDRESS",\r
43                       help="specify the interface to run on (default all "\r
44                            "interfaces)")\r
45     parser.add_option('-p', '--port', type="int", default=2121, metavar="PORT",\r
46                       help="specify port number to run on (default 2121)")\r
47     parser.add_option('-w', '--write', action="store_true", default=False,\r
48                       help="grants write access for logged in user "\r
49                            "(default read-only)")\r
50     parser.add_option('-d', '--directory', default=getcwdu(), metavar="FOLDER",\r
51                       help="specify the directory to share (default current "\r
52                            "directory)")\r
53     parser.add_option('-n', '--nat-address', default=None, metavar="ADDRESS",\r
54                       help="the NAT address to use for passive connections")\r
55     parser.add_option('-r', '--range', default=None, metavar="FROM-TO",\r
56                       help="the range of TCP ports to use for passive "\r
57                            "connections (e.g. -r 8000-9000)")\r
58     parser.add_option('-D', '--debug', action='store_true',\r
59                       help="enable DEBUG logging evel")\r
60     parser.add_option('-v', '--version', action='store_true',\r
61                       help="print pyftpdlib version and exit")\r
62     parser.add_option('-V', '--verbose', action='store_true',\r
63                       help="activate a more verbose logging")\r
64     parser.add_option('-u', '--username', type=str, default=None,\r
65                       help="specify username to login with (anonymous login "\r
66                            "will be disabled and password required "\r
67                            "if supplied)")\r
68     parser.add_option('-P', '--password', type=str, default=None,\r
69                       help="specify a password to login with (username "\r
70                            "required to be useful)")\r
71 \r
72     options, args = parser.parse_args()\r
73     if options.version:\r
74         sys.exit("pyftpdlib %s" % __ver__)\r
75     if options.debug:\r
76         config_logging(level=logging.DEBUG)\r
77 \r
78     passive_ports = None\r
79     if options.range:\r
80         try:\r
81             start, stop = options.range.split('-')\r
82             start = int(start)\r
83             stop = int(stop)\r
84         except ValueError:\r
85             parser.error('invalid argument passed to -r option')\r
86         else:\r
87             passive_ports = list(range(start, stop + 1))\r
88     # On recent Windows versions, if address is not specified and IPv6\r
89     # is installed the socket will listen on IPv6 by default; in this\r
90     # case we force IPv4 instead.\r
91     if os.name in ('nt', 'ce') and not options.interface:\r
92         options.interface = '0.0.0.0'\r
93 \r
94     authorizer = DummyAuthorizer()\r
95     perm = options.write and "elradfmwMT" or "elr"\r
96     if options.username:\r
97         if not options.password:\r
98             parser.error(\r
99                 "if username (-u) is supplied, password ('-P') is required")\r
100         authorizer.add_user(options.username,\r
101                             options.password,\r
102                             options.directory,\r
103                             perm=perm)\r
104     else:\r
105         authorizer.add_anonymous(options.directory, perm=perm)\r
106 \r
107     handler = FTPHandler\r
108     handler.authorizer = authorizer\r
109     handler.masquerade_address = options.nat_address\r
110     handler.passive_ports = passive_ports\r
111 \r
112     ftpd = FTPServer((options.interface, options.port), FTPHandler)\r
113     # On Windows specify a timeout for the underlying select() so\r
114     # that the server can be interrupted with CTRL + C.\r
115     try:\r
116         ftpd.serve_forever(timeout=2 if os.name == 'nt' else None)\r
117     finally:\r
118         ftpd.close_all()\r
119 \r
120 \r
121 if __name__ == '__main__':\r
122     main()\r