Ticket #2157: t-conch-t-python.patch

File t-conch-t-python.patch, 32.1 KB (added by John Popplewell, 6 years ago)

patches for cftp, conch scripts plus conch client, ssh, stdio, tap, python.win32

  • twisted/conch/client/default.py

     
    1313
    1414from twisted.python import log
    1515from twisted.python.filepath import FilePath
     16from twisted.python.runtime import platform
    1617
    1718from twisted.conch.error import ConchError
    1819from twisted.conch.ssh import common, keys, userauth
     
    3233# This name is bound so that the unit tests can use 'patch' to override it.
    3334_open = open
    3435
     36
     37class fakePTY(object):
     38    def __init__(self, fname, mode):
     39        pass
     40
     41    def close(self):
     42        pass
     43
     44    def read(self):
     45        pass
     46
     47    def readline(self):
     48        return raw_input()
     49
     50    def write(self, data):
     51        sys.stdout.write(data)
     52
     53if platform.isWindows():
     54    _open = fakePTY
     55
     56
    3557def verifyHostKey(transport, host, pubKey, fingerprint):
    3658    """
    3759    Verify a host's key.
     
    154176
    155177    def _getPassword(self, prompt):
    156178        try:
    157             oldout, oldin = sys.stdout, sys.stdin
    158             sys.stdin = sys.stdout = open('/dev/tty','r+')
    159             p=getpass.getpass(prompt)
    160             sys.stdout,sys.stdin=oldout,oldin
     179            if platform.isWindows():
     180                p = getpass.getpass(prompt)
     181            else:
     182                oldout, oldin = sys.stdout, sys.stdin
     183                sys.stdin = sys.stdout = open('/dev/tty','r+')
     184                p = getpass.getpass(prompt)
     185                sys.stdout, sys.stdin = oldout, oldin
    161186            return p
    162187        except (KeyboardInterrupt, IOError):
    163188            print
     
    244269    def getGenericAnswers(self, name, instruction, prompts):
    245270        responses = []
    246271        try:
    247             oldout, oldin = sys.stdout, sys.stdin
    248             sys.stdin = sys.stdout = open('/dev/tty','r+')
     272            if not platform.isWindows():
     273                oldout, oldin = sys.stdout, sys.stdin
     274                sys.stdin = sys.stdout = open('/dev/tty','r+')
    249275            if name:
    250276                print name
    251277            if instruction:
     
    256282                else:
    257283                    responses.append(getpass.getpass(prompt))
    258284        finally:
    259             sys.stdout,sys.stdin=oldout,oldin
     285            if not platform.isWindows():
     286                sys.stdout,sys.stdin=oldout,oldin
    260287        return defer.succeed(responses)
     288
  • twisted/conch/scripts/cftp.py

     
    66Implementation module for the I{cftp} command.
    77"""
    88
    9 import os, sys, getpass, struct, tty, fcntl, stat
    10 import fnmatch, pwd, glob
     9import os, sys, getpass, struct, stat
     10from twisted.python.win32 import tty, fcntl
    1111
     12try:
     13    import pwd
     14except ImportError:
     15    pwd = None
     16
     17import fnmatch, glob
     18import posixpath
     19
    1220from twisted.conch.client import connect, default, options
    1321from twisted.conch.ssh import connection, common
    1422from twisted.conch.ssh import channel, filetransfer
    1523from twisted.protocols import basic
    1624from twisted.internet import reactor, stdio, defer, utils
    1725from twisted.python import log, usage, failure
     26from twisted.python.runtime import platform
    1827
    1928class ClientOptions(options.ConchOptions):
    2029
     
    124133    def __getattr__(self, attr):
    125134        return getattr(self.f, attr)
    126135
     136
    127137class StdioClient(basic.LineReceiver):
    128138
    129139    _pwd = pwd
    130140
    131141    ps = 'cftp> '
    132     delimiter = '\n'
     142    from os import linesep as delimiter
    133143
    134144    reactor = reactor
    135145
     
    140150        self.useProgressBar = (not f and 1) or 0
    141151
    142152    def connectionMade(self):
    143         self.client.realPath('').addCallback(self._cbSetCurDir)
     153        d = self.client.realPath('')
     154        d.addCallback(self._cbSetCurDir)
     155        d.addErrback(self._ebSetCurDir)
    144156
     157    def _ebSetCurDir(self, f):
     158        self._printFailure(f)
     159
    145160    def _cbSetCurDir(self, path):
    146161        self.currentDirectory = path
    147162        self._newLine()
     
    164179            d.addCallback(self._cbCommand)
    165180            d.addErrback(self._ebCommand)
    166181
    167 
    168182    def _dispatchCommand(self, line):
    169183        if ' ' in line:
    170184            command, rest = line.split(' ', 1)
     
    175189            f = self.cmd_EXEC
    176190            rest = (command[1:] + ' ' + rest).strip()
    177191        else:
    178             command = command.upper()
    179             log.msg('looking up cmd %s' % command)
    180             f = getattr(self, 'cmd_%s' % command, None)
     192            cmd = command.upper()
     193            log.msg('looking up cmd %s' % cmd)
     194            f = getattr(self, 'cmd_%s' % cmd, None)
    181195        if f is not None:
    182196            return defer.maybeDeferred(f, rest)
    183197        else:
    184198            self._ebCommand(failure.Failure(NotImplementedError(
    185199                "No command called `%s'" % command)))
    186             self._newLine()
    187200
    188201    def _printFailure(self, f):
    189202        log.msg(f)
    190203        e = f.trap(NotImplementedError, filetransfer.SFTPError, OSError, IOError)
    191204        if e == NotImplementedError:
     205            self.transport.write(f.getErrorMessage()+os.linesep)
    192206            self.transport.write(self.cmd_HELP(''))
    193207        elif e == filetransfer.SFTPError:
    194208            self.transport.write("remote error %i: %s\n" %
     
    227241        path, rest = self._getFilename(path)
    228242        if not path.endswith('/'):
    229243            path += '/'
    230         newPath = path and os.path.join(self.currentDirectory, path) or ''
     244        newPath = path and posixpath.join(self.currentDirectory, path) or ''
    231245        d = self.client.openDirectory(newPath)
    232246        d.addCallback(self._cbCd)
    233247        d.addErrback(self._ebCommand)
     
    283297                    return "Wildcard get with non-directory target."
    284298            else:
    285299                local = ''
     300            head, tail = os.path.split(remote)
     301            if not head:
     302                remote = posixpath.join(self.currentDirectory, remote)
    286303            d = self._remoteGlob(remote)
    287304            d.addCallback(self._cbGetMultiple, local)
    288305            return d
     
    291308        else:
    292309            local = os.path.split(remote)[1]
    293310        log.msg((remote, local))
    294         lf = file(local, 'w', 0)
    295         path = os.path.join(self.currentDirectory, remote)
     311        lf = file(local, 'wb', 0)
     312        path = posixpath.join(self.currentDirectory, remote)
    296313        d = self.client.openFile(path, filetransfer.FXF_READ, {})
    297314        d.addCallback(self._cbGetOpenFile, lf)
    298315        d.addErrback(self._ebCloseLf, lf)
     
    313330        if not files:
    314331            return
    315332        f = files.pop(0)[0]
    316         lf = file(os.path.join(local, os.path.split(f)[1]), 'w', 0)
    317         path = os.path.join(self.currentDirectory, f)
     333        lf = file(os.path.join(local, os.path.split(f)[1]), 'wb', 0)
     334        path = posixpath.join(self.currentDirectory, f)
    318335        d = self.client.openFile(path, filetransfer.FXF_READ, {})
    319336        d.addCallback(self._cbGetOpenFile, lf)
    320337        d.addErrback(self._ebCloseLf, lf)
     
    405422        if '*' in local or '?' in local: # wildcard
    406423            if rest:
    407424                remote, rest = self._getFilename(rest)
    408                 path = os.path.join(self.currentDirectory, remote)
     425                path = posixpath.join(self.currentDirectory, remote)
    409426                d = self.client.getAttrs(path)
    410427                d.addCallback(self._cbPutTargetAttrs, remote, local)
    411428                return d
     
    417434            remote, rest = self._getFilename(rest)
    418435        else:
    419436            remote = os.path.split(local)[1]
    420         lf = file(local, 'r')
    421         path = os.path.join(self.currentDirectory, remote)
     437        lf = file(local, 'rb')
     438        path = posixpath.join(self.currentDirectory, remote)
    422439        flags = filetransfer.FXF_WRITE|filetransfer.FXF_CREAT|filetransfer.FXF_TRUNC
    423440        d = self.client.openFile(path, flags, {})
    424441        d.addCallback(self._cbPutOpenFile, lf)
     
    441458        while files and not f:
    442459            try:
    443460                f = files.pop(0)
    444                 lf = file(f, 'r')
     461                lf = file(f, 'rb')
    445462            except:
    446463                self._printFailure(failure.Failure())
    447464                f = None
    448465        if not f:
    449466            return
    450467        name = os.path.split(f)[1]
    451         remote = os.path.join(self.currentDirectory, path, name)
     468        remote = posixpath.join(self.currentDirectory, path, name)
    452469        log.msg((name, remote, path))
    453470        flags = filetransfer.FXF_WRITE|filetransfer.FXF_CREAT|filetransfer.FXF_TRUNC
    454471        d = self.client.openFile(remote, flags, {})
     
    501518        linkpath, rest = self._getFilename(rest)
    502519        targetpath, rest = self._getFilename(rest)
    503520        linkpath, targetpath = map(
    504                 lambda x: os.path.join(self.currentDirectory, x),
     521                lambda x: posixpath.join(self.currentDirectory, x),
    505522                (linkpath, targetpath))
    506523        return self.client.makeLink(linkpath, targetpath).addCallback(_ignore)
    507524
     
    525542        if not path:
    526543            fullPath = self.currentDirectory + '/'
    527544        else:
    528             fullPath = os.path.join(self.currentDirectory, path)
     545            fullPath = posixpath.join(self.currentDirectory, path)
    529546        d = self._remoteGlob(fullPath)
    530547        d.addCallback(self._cbDisplayFiles, options)
     548        d.addErrback(self._ebCommand)
    531549        return d
    532550
    533551    def _cbDisplayFiles(self, files, options):
     
    545563
    546564    def cmd_MKDIR(self, path):
    547565        path, rest = self._getFilename(path)
    548         path = os.path.join(self.currentDirectory, path)
     566        path = posixpath.join(self.currentDirectory, path)
    549567        return self.client.makeDirectory(path, {}).addCallback(_ignore)
    550568
    551569    def cmd_RMDIR(self, path):
    552570        path, rest = self._getFilename(path)
    553         path = os.path.join(self.currentDirectory, path)
     571        path = posixpath.join(self.currentDirectory, path)
    554572        return self.client.removeDirectory(path).addCallback(_ignore)
    555573
    556574    def cmd_LMKDIR(self, path):
    557         os.system("mkdir %s" % path)
     575        if platform.isWindows():
     576            os.mkdir(path)
     577        else:
     578            os.system("mkdir %s" % path)
    558579
    559580    def cmd_RM(self, path):
    560581        path, rest = self._getFilename(path)
    561         path = os.path.join(self.currentDirectory, path)
     582        path = posixpath.join(self.currentDirectory, path)
    562583        return self.client.removeFile(path).addCallback(_ignore)
    563584
    564585    def cmd_LLS(self, rest):
     
    568589        oldpath, rest = self._getFilename(rest)
    569590        newpath, rest = self._getFilename(rest)
    570591        oldpath, newpath = map (
    571                 lambda x: os.path.join(self.currentDirectory, x),
     592                lambda x: posixpath.join(self.currentDirectory, x),
    572593                (oldpath, newpath))
    573594        return self.client.renameFile(oldpath, newpath).addCallback(_ignore)
    574595
     
    622643        Run C{rest} using the user's shell (or /bin/sh if they do not have
    623644        one).
    624645        """
    625         shell = self._pwd.getpwnam(getpass.getuser())[6]
    626         if not shell:
    627             shell = '/bin/sh'
    628         if rest:
    629             cmds = ['-c', rest]
    630             return utils.getProcessOutput(shell, cmds, errortoo=1)
     646        if not platform.isWindows():
     647            shell = self._pwd.getpwnam(getpass.getuser())[6]
     648            if not shell:
     649                shell = '/bin/sh'
     650            if rest:
     651                cmds = ['-c', rest]
     652                return utils.getProcessOutput(shell, cmds, errortoo=1)
    631653        else:
    632             os.system(shell)
     654            # The tests do a lot of monkey business so this is messier than
     655            # it needs to be in real-life. On Linux the '-c' flag works for
     656            # bash and python. Sadly 'cmd.exe' only accepts '/c' and 'python.exe'
     657            # only accepts '-c'.
     658            shell = None
     659            if self._pwd:
     660                shell = self._pwd.getpwnam(getpass.getuser())[6]
     661            if not shell:
     662                shell = os.environ['COMSPEC']
     663            if rest:
     664                if shell == os.environ['COMSPEC']:
     665                    opt = '/c'  # for cmd.exe
     666                else:
     667                    opt = '-c'  # for python.exe
     668                cmds = [opt, rest]
     669                return utils.getProcessOutput(shell, cmds, errortoo=1)
     670        os.system(shell)
    633671
    634672    # accessory functions
    635673
     
    798836        if self.conn.options['batchfile']:
    799837            fn = self.conn.options['batchfile']
    800838            if fn != '-':
    801                 f = file(fn)
     839                f = file(fn, "rb")
    802840        self.stdio = stdio.StandardIO(StdioClient(self.client, f))
    803841
    804842    def extReceived(self, t, data):
  • twisted/conch/scripts/conch.py

     
    44# See LICENSE for details.
    55
    66#
    7 # $Id: conch.py,v 1.65 2004/03/11 00:29:14 z3p Exp $
     7# $Id: conch.py,v 1.3 2013/04/17 06:05:26 jfp Exp $
    88
    99#""" Implementation module for the `conch` command.
    1010#"""
     
    1414from twisted.conch.ssh import session, forwarding, channel
    1515from twisted.internet import reactor, stdio, task
    1616from twisted.python import log, usage
     17from twisted.python.runtime import platform
    1718
    18 import os, sys, getpass, struct, tty, fcntl, signal
     19import os, sys, getpass, struct, signal
     20from twisted.python.win32 import tty, fcntl
    1921
    2022class ClientOptions(options.ConchOptions):
    2123
     
    3638                 ['noshell', 'N', 'Do not execute a shell or command.'],
    3739                 ['subsystem', 's', 'Invoke command (mandatory) as SSH2 subsystem.'],
    3840                ]
     41    if platform.isWindows():
     42        del optFlags[1]
    3943
    4044    compData = usage.Completions(
    4145        mutuallyExclusive=[("tty", "notty")],
     
    139143        if oldUSR1:
    140144            signal.signal(signal.SIGUSR1, oldUSR1)
    141145        if (options['command'] and options['tty']) or not options['notty']:
    142             signal.signal(signal.SIGWINCH, signal.SIG_DFL)
     146            try:
     147                signal.signal(signal.SIGWINCH, signal.SIG_DFL)
     148            except AttributeError:
     149                pass
    143150    if sys.stdout.isatty() and not options['command']:
    144151        print 'Connection to %s closed.' % options['host']
    145152    sys.exit(exitStatus)
     
    361368                common.NS(options['command']))
    362369        elif options['command']:
    363370            if options['tty']:
    364                 term = os.environ['TERM']
    365371                winsz = fcntl.ioctl(fd, tty.TIOCGWINSZ, '12345678')
    366372                winSize = struct.unpack('4H', winsz)
     373                if platform.isWindows():
     374                    term = "dumb"
     375                else:
     376                    term = os.environ['TERM']
     377                    signal.signal(signal.SIGWINCH, self._windowResized)
    367378                ptyReqData = session.packRequest_pty_req(term, winSize, '')
    368379                self.conn.sendRequest(self, 'pty-req', ptyReqData)
    369                 signal.signal(signal.SIGWINCH, self._windowResized)
    370             self.conn.sendRequest(self, 'exec', \
    371                 common.NS(options['command']))
     380            self.conn.sendRequest(self, 'exec', common.NS(options['command']))
    372381        else:
    373382            if not options['notty']:
    374                 term = os.environ['TERM']
    375383                winsz = fcntl.ioctl(fd, tty.TIOCGWINSZ, '12345678')
    376384                winSize = struct.unpack('4H', winsz)
     385                if platform.isWindows():
     386                    term = "dumb"
     387                else:
     388                    term = os.environ['TERM']
     389                    signal.signal(signal.SIGWINCH, self._windowResized)
    377390                ptyReqData = session.packRequest_pty_req(term, winSize, '')
    378391                self.conn.sendRequest(self, 'pty-req', ptyReqData)
    379                 signal.signal(signal.SIGWINCH, self._windowResized)
    380392            self.conn.sendRequest(self, 'shell', '')
    381             #if hasattr(conn.transport, 'transport'):
    382             #    conn.transport.transport.setTcpNoDelay(1)
    383393
    384394    def handleInput(self, char):
    385395        #log.msg('handling %s' % repr(char))
     
    455465        self.stdio.resumeProducing()
    456466
    457467    def _windowResized(self, *args):
     468        if not fcntl:
     469            return
    458470        winsz = fcntl.ioctl(0, tty.TIOCGWINSZ, '12345678')
    459471        winSize = struct.unpack('4H', winsz)
    460472        newSize = winSize[1], winSize[0], winSize[2], winSize[3]
  • twisted/conch/ssh/filetransfer.py

     
    88
    99from twisted.internet import defer, protocol
    1010from twisted.python import failure, log
     11from twisted.python.runtime import platform
     12from twisted.python.win32 import WindowsError
    1113
    1214from common import NS, getNS
    1315from twisted.conch.interfaces import ISFTPServer, ISFTPFile
     
    415417    def _ebStatus(self, reason, requestId, msg = "request failed"):
    416418        code = FX_FAILURE
    417419        message = msg
    418         if reason.type in (IOError, OSError):
     420        if reason.type is WindowsError:
     421            if reason.value.winerror == 2: # no such file
     422                code = FX_NO_SUCH_FILE
     423                message = reason.value.strerror
     424            elif reason.value.winerror == 123: # invalid filename
     425                code = FX_NO_SUCH_FILE
     426                message = reason.value.strerror
     427            elif reason.value.winerror == 267: # invalid directory name
     428                code = FX_NOT_A_DIRECTORY
     429                message = reason.value.strerror
     430            elif reason.value.winerror == 183: # directory already exists
     431                code = FX_FILE_ALREADY_EXISTS
     432            else:
     433                log.err(reason)
     434        elif reason.type in (IOError, OSError):
     435            if reason.value.errno in (errno.ENOTEMPTY, errno.EINVAL):
     436                code = FX_FAILURE
     437                message = reason.value.strerror
    419438            if reason.value.errno == errno.ENOENT: # no such file
    420439                code = FX_NO_SUCH_FILE
    421440                message = reason.value.strerror
    422             elif reason.value.errno == errno.EACCES: # permission denied
     441            elif reason.value.errno in (errno.EACCES, errno.EPERM): # permission denied
    423442                code = FX_PERMISSION_DENIED
    424443                message = reason.value.strerror
    425444            elif reason.value.errno == errno.EEXIST:
     
    472491        to be sent to the server.
    473492        """
    474493        FileTransferBase.__init__(self)
    475         self.extData = {}
     494        self.extData = extData
    476495        self.counter = 0
    477496        self.openRequests = {} # id -> Deferred
    478497        self.wasAFile = {} # Deferred -> 1 TERRIBLE HACK
    479498
    480499    def connectionMade(self):
    481500        data = struct.pack('!L', max(self.versions))
    482         for k,v in self.extData.itervalues():
     501        for k,v in self.extData.iteritems():
    483502            data += NS(k) + NS(v)
    484503        self.sendPacket(FXP_INIT, data)
    485504
  • twisted/conch/stdio.py

     
    88@author: Jp Calderone
    99"""
    1010
    11 import os, tty, sys, termios
     11import os, sys
     12try:
     13    import tty, termios
     14except ImportError:
     15    tty = termios = None
    1216
    1317from twisted.internet import reactor, stdio, protocol, defer
    1418from twisted.python import failure, reflect, log
     
    4347
    4448    def childConnectionLost(self, childFD):
    4549        if self.proto is not None:
    46             self.proto.childConnectionLost(childFD)
     50            try:
     51                self.proto.childConnectionLost(childFD)
     52            except:
     53                pass
    4754
    4855    def processEnded(self, reason):
    4956        if self.proto is not None:
     
    6673
    6774
    6875def runWithProtocol(klass):
    69     fd = sys.__stdin__.fileno()
    70     oldSettings = termios.tcgetattr(fd)
    71     tty.setraw(fd)
     76    if termios:
     77        fd = sys.__stdin__.fileno()
     78        oldSettings = termios.tcgetattr(fd)
     79        tty.setraw(fd)
    7280    try:
    7381        p = ServerProtocol(klass)
    7482        stdio.StandardIO(p)
    7583        reactor.run()
    7684    finally:
    77         termios.tcsetattr(fd, termios.TCSANOW, oldSettings)
    78         os.write(fd, "\r\x1bc\r")
     85        if termios:
     86            termios.tcsetattr(fd, termios.TCSANOW, oldSettings)
     87            os.write(fd, "\r\x1bc\r")
    7988
    8089
    8190
    8291def main(argv=None):
    83     log.startLogging(file('child.log', 'w'))
     92    log.startLogging(file('child.log', 'wb'))
    8493
    8594    if argv is None:
    8695        argv = sys.argv[1:]
  • twisted/conch/tap.py

     
    55"""
    66Support module for making SSH servers with twistd.
    77"""
     8import sys
     9from twisted.python.runtime import platform
    810
    9 from twisted.conch import unix
     11if platform.isWindows():
     12    from twisted.conch.windows import WindowsSSHRealm as SSHRealm
     13else:
     14    from twisted.conch.unix import UnixSSHRealm as SSHRealm
     15
    1016from twisted.conch import checkers as conch_checkers
    1117from twisted.conch.openssh_compat import factory
    1218from twisted.cred import portal, checkers, strcred
     
    8086
    8187    t = factory.OpenSSHFactory()
    8288
    83     r = unix.UnixSSHRealm()
     89    r = SSHRealm()
    8490    t.portal = portal.Portal(r, config.get('credCheckers', []))
    8591    t.dataRoot = config['data']
    8692    t.moduliRoot = config['moduli'] or config['data']
  • twisted/python/win32.py

     
    1515
    1616import re
    1717import os
     18import struct
    1819
    1920try:
    2021    import win32api
     
    2223except ImportError:
    2324    pass
    2425
     26try:
     27    from twisted.internet import win32conio
     28except ImportError:
     29    pass
     30
    2531from twisted.python.runtime import platform
    2632
    2733# http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/system_error_codes.asp
     
    167173        return os.strerror(errorcode)
    168174
    169175formatError = _ErrorFormatter.fromEnvironment().formatError
     176
     177class FakeFcntl(object):
     178    """This *fake* module is for windows only
     179    """
     180    DN_ACCESS       = 1
     181    DN_ATTRIB       = 32
     182    DN_CREATE       = 4
     183    DN_DELETE       = 8
     184    DN_MODIFY       = 2
     185    DN_MULTISHOT    = -2147483648
     186    DN_RENAME       = 16
     187    FASYNC          = 8192
     188    FD_CLOEXEC      = 1
     189    F_DUPFD         = 0
     190    F_EXLCK         = 4
     191    F_GETFD         = 1
     192    F_GETFL         = 3
     193    F_GETLEASE      = 1025
     194    F_GETLK         = 12
     195    F_GETLK64       = 12
     196    F_GETOWN        = 9
     197    F_GETSIG        = 11
     198    F_NOTIFY        = 1026
     199    F_RDLCK         = 0
     200    F_SETFD         = 2
     201    F_SETFL         = 4
     202    F_SETLEASE      = 1024
     203    F_SETLK         = 13
     204    F_SETLK64       = 13
     205    F_SETLKW        = 14
     206    F_SETLKW64      = 14
     207    F_SETOWN        = 8
     208    F_SETSIG        = 10
     209    F_SHLCK         = 8
     210    F_UNLCK         = 2
     211    F_WRLCK         = 1
     212    I_ATMARK        = 21279
     213    I_CANPUT        = 21282
     214    I_CKBAND        = 21277
     215    I_FDINSERT      = 21264
     216    I_FIND          = 21259
     217    I_FLUSH         = 21253
     218    I_FLUSHBAND     = 21276
     219    I_GETBAND       = 21278
     220    I_GETCLTIME     = 21281
     221    I_GETSIG        = 21258
     222    I_GRDOPT        = 21255
     223    I_GWROPT        = 21268
     224    I_LINK          = 21260
     225    I_LIST          = 21269
     226    I_LOOK          = 21252
     227    I_NREAD         = 21249
     228    I_PEEK          = 21263
     229    I_PLINK         = 21270
     230    I_POP           = 21251
     231    I_PUNLINK       = 21271
     232    I_PUSH          = 21250
     233    I_RECVFD        = 21262
     234    I_SENDFD        = 21265
     235    I_SETCLTIME     = 21280
     236    I_SETSIG        = 21257
     237    I_SRDOPT        = 21254
     238    I_STR           = 21256
     239    I_SWROPT        = 21267
     240    I_UNLINK        = 21261
     241    LOCK_EX         = 2
     242    LOCK_MAND       = 32
     243    LOCK_NB         = 4
     244    LOCK_READ       = 64
     245    LOCK_RW         = 192
     246    LOCK_SH         = 1
     247    LOCK_UN         = 8
     248    LOCK_WRITE      = 128
     249
     250    def fcntl(self, fd, op, arg=0):
     251        raise NotImplementedError
     252    def ioctl(self, fd, op, arg=0, mutate_flag=True):
     253        if op == tty.TIOCGWINSZ:
     254            width, height = win32conio.getWindowSize()
     255            return struct.pack("4H", height, width, 0, 0)
     256        else:
     257            raise NotImplementedError
     258    def flock(self, fd, op):
     259        raise NotImplementedError
     260    def lockf(self, fd, op, length=0, start=0, whence=0):
     261        raise NotImplementedError
     262
     263
     264class FakeTermios(object):
     265    B0                  = 0
     266    B110                = 3
     267    B115200             = 4098
     268    B1200               = 9
     269    B134                = 4
     270    B150                = 5
     271    B1800               = 10
     272    B19200              = 14
     273    B200                = 6
     274    B230400             = 4099
     275    B2400               = 11
     276    B300                = 7
     277    B38400              = 15
     278    B460800             = 4100
     279    B4800               = 12
     280    B50                 = 1
     281    B57600              = 4097
     282    B600                = 8
     283    B75                 = 2
     284    B9600               = 13
     285    BRKINT              = 2
     286    BS0                 = 0
     287    BS1                 = 8192
     288    BSDLY               = 8192
     289    CBAUD               = 4111
     290    CBAUDEX             = 4096
     291    CDSUSP              = 25
     292    CEOF                = 4
     293    CEOL                = 0
     294    CEOT                = 4
     295    CERASE              = 127
     296    CFLUSH              = 15
     297    CIBAUD              = 269418496
     298    CINTR               = 3
     299    CKILL               = 21
     300    CLNEXT              = 22
     301    CLOCAL              = 2048
     302    CQUIT               = 28
     303    CR0                 = 0
     304    CR1                 = 512
     305    CR2                 = 1024
     306    CR3                 = 1536
     307    CRDLY               = 1536
     308    CREAD               = 128
     309    CRPRNT              = 18
     310    CRTSCTS             = -2147483648
     311    CS5                 = 0
     312    CS6                 = 16
     313    CS7                 = 32
     314    CS8                 = 48
     315    CSIZE               = 48
     316    CSTART              = 17
     317    CSTOP               = 19
     318    CSTOPB              = 64
     319    CSUSP               = 26
     320    CWERASE             = 23
     321    ECHO                = 8
     322    ECHOCTL             = 512
     323    ECHOE               = 16
     324    ECHOK               = 32
     325    ECHOKE              = 2048
     326    ECHONL              = 64
     327    ECHOPRT             = 1024
     328    EXTA                = 14
     329    EXTB                = 15
     330    FF0                 = 0
     331    FF1                 = 32768
     332    FFDLY               = 32768
     333    FIOASYNC            = 21586
     334    FIOCLEX             = 21585
     335    FIONBIO             = 21537
     336    FIONCLEX            = 21584
     337    FIONREAD            = 21531
     338    FLUSHO              = 4096
     339    HUPCL               = 1024
     340    ICANON              = 2
     341    ICRNL               = 256
     342    IEXTEN              = 32768
     343    IGNBRK              = 1
     344    IGNCR               = 128
     345    IGNPAR              = 4
     346    IMAXBEL             = 8192
     347    INLCR               = 64
     348    INPCK               = 16
     349    IOCSIZE_MASK        = 1073676288
     350    IOCSIZE_SHIFT       = 16
     351    ISIG                = 1
     352    ISTRIP              = 32
     353    IUCLC               = 512
     354    IXANY               = 2048
     355    IXOFF               = 4096
     356    IXON                = 1024
     357    NCC                 = 8
     358    NCCS                = 32
     359    NL0                 = 0
     360    NL1                 = 256
     361    NLDLY               = 256
     362    NOFLSH              = 128
     363    N_MOUSE             = 2
     364    N_PPP               = 3
     365    N_SLIP              = 1
     366    N_STRIP             = 4
     367    N_TTY               = 0
     368    OCRNL               = 8
     369    OFDEL               = 128
     370    OFILL               = 64
     371    OLCUC               = 2
     372    ONLCR               = 4
     373    ONLRET              = 32
     374    ONOCR               = 16
     375    OPOST               = 1
     376    PARENB              = 256
     377    PARMRK              = 8
     378    PARODD              = 512
     379    PENDIN              = 16384
     380    TAB0                = 0
     381    TAB1                = 2048
     382    TAB2                = 4096
     383    TAB3                = 6144
     384    TABDLY              = 6144
     385    TCFLSH              = 21515
     386    TCGETA              = 21509
     387    TCGETS              = 21505
     388    TCIFLUSH            = 0
     389    TCIOFF              = 2
     390    TCIOFLUSH           = 2
     391    TCION               = 3
     392    TCOFLUSH            = 1
     393    TCOOFF              = 0
     394    TCOON               = 1
     395    TCSADRAIN           = 1
     396    TCSAFLUSH           = 2
     397    TCSANOW             = 0
     398    TCSBRK              = 21513
     399    TCSBRKP             = 21541
     400    TCSETA              = 21510
     401    TCSETAF             = 21512
     402    TCSETAW             = 21511
     403    TCSETS              = 21506
     404    TCSETSF             = 21508
     405    TCSETSW             = 21507
     406    TCXONC              = 21514
     407    TIOCCONS            = 21533
     408    TIOCEXCL            = 21516
     409    TIOCGETD            = 21540
     410    TIOCGICOUNT         = 21597
     411    TIOCGLCKTRMIOS      = 21590
     412    TIOCGPGRP           = 21519
     413    TIOCGSERIAL         = 21534
     414    TIOCGSOFTCAR        = 21529
     415    TIOCGWINSZ          = 21523
     416    TIOCINQ             = 21531
     417    TIOCLINUX           = 21532
     418    TIOCMBIC            = 21527
     419    TIOCMBIS            = 21526
     420    TIOCMGET            = 21525
     421    TIOCMIWAIT          = 21596
     422    TIOCMSET            = 21528
     423    TIOCM_CAR           = 64
     424    TIOCM_CD            = 64
     425    TIOCM_CTS           = 32
     426    TIOCM_DSR           = 256
     427    TIOCM_DTR           = 2
     428    TIOCM_LE            = 1
     429    TIOCM_RI            = 128
     430    TIOCM_RNG           = 128
     431    TIOCM_RTS           = 4
     432    TIOCM_SR            = 16
     433    TIOCM_ST            = 8
     434    TIOCNOTTY           = 21538
     435    TIOCNXCL            = 21517
     436    TIOCOUTQ            = 21521
     437    TIOCPKT             = 21536
     438    TIOCPKT_DATA        = 0
     439    TIOCPKT_DOSTOP      = 32
     440    TIOCPKT_FLUSHREAD   = 1
     441    TIOCPKT_FLUSHWRITE  = 2
     442    TIOCPKT_NOSTOP      = 16
     443    TIOCPKT_START       = 8
     444    TIOCPKT_STOP        = 4
     445    TIOCSCTTY           = 21518
     446    TIOCSERCONFIG       = 21587
     447    TIOCSERGETLSR       = 21593
     448    TIOCSERGETMULTI     = 21594
     449    TIOCSERGSTRUCT      = 21592
     450    TIOCSERGWILD        = 21588
     451    TIOCSERSETMULTI     = 21595
     452    TIOCSERSWILD        = 21589
     453    TIOCSER_TEMT        = 1
     454    TIOCSETD            = 21539
     455    TIOCSLCKTRMIOS      = 21591
     456    TIOCSPGRP           = 21520
     457    TIOCSSERIAL         = 21535
     458    TIOCSSOFTCAR        = 21530
     459    TIOCSTI             = 21522
     460    TIOCSWINSZ          = 21524
     461    TOSTOP              = 256
     462    VDISCARD            = 13
     463    VEOF                = 4
     464    VEOL                = 11
     465    VEOL2               = 16
     466    VERASE              = 2
     467    VINTR               = 0
     468    VKILL               = 3
     469    VLNEXT              = 15
     470    VMIN                = 6
     471    VQUIT               = 1
     472    VREPRINT            = 12
     473    VSTART              = 8
     474    VSTOP               = 9
     475    VSUSP               = 10
     476    VSWTC               = 7
     477    VSWTCH              = 7
     478    VT0                 = 0
     479    VT1                 = 16384
     480    VTDLY               = 16384
     481    VTIME               = 5
     482    VWERASE             = 14
     483    XCASE               = 4
     484    XTABS               = 6144
     485
     486    class error(Exception):
     487        pass
     488
     489    def tcdrain(self, fd):
     490        raise NotImplementedError
     491
     492    def tcflow(self, fd, action):
     493        raise NotImplementedError
     494
     495    def tcflush(self, fd, queue):
     496        raise NotImplementedError
     497
     498    def tcgetattr(self, fd):
     499        raise NotImplementedError
     500
     501    def tcsendbreak(self, fd, duration):
     502        raise NotImplementedError
     503
     504    def tcsetattr(self, fd, when, attributes):
     505        raise NotImplementedError
     506
     507
     508class FakeTTY(FakeTermios):
     509    IFLAG   = 0
     510    OFLAG   = 1
     511    CFLAG   = 2
     512    LFLAG   = 3
     513    ISPEED  = 4
     514    OSPEED  = 5
     515    CC      = 6
     516
     517    def setcbreak(self, fd, when=FakeTermios.TCSAFLUSH):
     518        raise NotImplementedError
     519
     520    def setraw(self, fd, when=FakeTermios.TCSAFLUSH):
     521        raise NotImplementedError
     522
     523
     524try:
     525    import fcntl
     526except ImportError:
     527    fcntl = FakeFcntl()
     528
     529try:
     530    import termios
     531except ImportError:
     532    termios = FakeTermios()
     533
     534try:
     535    import tty
     536except ImportError:
     537    tty = FakeTTY()
     538