__main__.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. #!/usr/bin/env python
  2. # $Id: __main__.py 1206 2013-04-06 15:26:00Z g.rodola $
  3. # ======================================================================
  4. # Copyright (C) 2007-2013 Giampaolo Rodola' <g.rodola@gmail.com>
  5. #
  6. # All Rights Reserved
  7. #
  8. # Permission is hereby granted, free of charge, to any person
  9. # obtaining a copy of this software and associated documentation
  10. # files (the "Software"), to deal in the Software without
  11. # restriction, including without limitation the rights to use,
  12. # copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. # copies of the Software, and to permit persons to whom the
  14. # Software is furnished to do so, subject to the following
  15. # conditions:
  16. #
  17. # The above copyright notice and this permission notice shall be
  18. # included in all copies or substantial portions of the Software.
  19. #
  20. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  22. # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  24. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  25. # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  26. # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  27. # OTHER DEALINGS IN THE SOFTWARE.
  28. #
  29. # ======================================================================
  30. """
  31. Start a stand alone anonymous FTP server from the command line as in:
  32. $ python -m pyftpdlib
  33. """
  34. import optparse
  35. import sys
  36. import os
  37. from pyftpdlib import __ver__
  38. from pyftpdlib.authorizers import DummyAuthorizer
  39. from pyftpdlib.handlers import FTPHandler
  40. from pyftpdlib.servers import FTPServer
  41. from pyftpdlib._compat import getcwdu
  42. class CustomizedOptionFormatter(optparse.IndentedHelpFormatter):
  43. """Formats options shown in help in a prettier way."""
  44. def format_option(self, option):
  45. result = []
  46. opts = self.option_strings[option]
  47. result.append(' %s\n' % opts)
  48. if option.help:
  49. help_text = ' %s\n\n' % self.expand_default(option)
  50. result.append(help_text)
  51. return ''.join(result)
  52. def main():
  53. """Start a stand alone anonymous FTP server."""
  54. usage = "python -m pyftpdlib.ftpserver [options]"
  55. parser = optparse.OptionParser(usage=usage, description=main.__doc__,
  56. formatter=CustomizedOptionFormatter())
  57. parser.add_option('-i', '--interface', default=None, metavar="ADDRESS",
  58. help="specify the interface to run on (default all "
  59. "interfaces)")
  60. parser.add_option('-p', '--port', type="int", default=2121, metavar="PORT",
  61. help="specify port number to run on (default 21)")
  62. parser.add_option('-w', '--write', action="store_true", default=False,
  63. help="grants write access for the anonymous user "
  64. "(default read-only)")
  65. parser.add_option('-d', '--directory', default=getcwdu(), metavar="FOLDER",
  66. help="specify the directory to share (default current "
  67. "directory)")
  68. parser.add_option('-n', '--nat-address', default=None, metavar="ADDRESS",
  69. help="the NAT address to use for passive connections")
  70. parser.add_option('-r', '--range', default=None, metavar="FROM-TO",
  71. help="the range of TCP ports to use for passive "
  72. "connections (e.g. -r 8000-9000)")
  73. parser.add_option('-v', '--version', action='store_true',
  74. help="print pyftpdlib version and exit")
  75. options, args = parser.parse_args()
  76. if options.version:
  77. sys.exit("pyftpdlib %s" % __ver__)
  78. passive_ports = None
  79. if options.range:
  80. try:
  81. start, stop = options.range.split('-')
  82. start = int(start)
  83. stop = int(stop)
  84. except ValueError:
  85. parser.error('invalid argument passed to -r option')
  86. else:
  87. passive_ports = list(range(start, stop + 1))
  88. # On recent Windows versions, if address is not specified and IPv6
  89. # is installed the socket will listen on IPv6 by default; in this
  90. # case we force IPv4 instead.
  91. if os.name in ('nt', 'ce') and not options.interface:
  92. options.interface = '0.0.0.0'
  93. authorizer = DummyAuthorizer()
  94. perm = options.write and "elradfmwM" or "elr"
  95. authorizer.add_anonymous(options.directory, perm=perm)
  96. handler = FTPHandler
  97. handler.authorizer = authorizer
  98. handler.masquerade_address = options.nat_address
  99. handler.passive_ports = passive_ports
  100. ftpd = FTPServer((options.interface, options.port), FTPHandler)
  101. try:
  102. ftpd.serve_forever()
  103. finally:
  104. ftpd.close_all()
  105. if __name__ == '__main__':
  106. main()