User Tools

Site Tools


coding:utilities

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
coding:utilities [2008/07/31 12:38]
127.0.0.1 external edit
coding:utilities [2011/03/02 13:40] (current)
robm IE2FF comments fix
Line 1: Line 1:
 ====== Utilities ====== ====== Utilities ======
 A collection of scripts and the like which I have come to rely on. A collection of scripts and the like which I have come to rely on.
 +
 +===== IE2FF =====
 +<code python>
 +#!/usr/bin/env python
 +"""
 +URL-click forwarder (Windows -> Linux).
 +
 +This script catches URL clicks (actually iexplore.exe invokations) and 
 +forwards them over TCP/IP to a Linux machine which launches them in the 
 +default browser (e.g. Firefox).
 +
 +This was written so that clicking a URL in, say, MS Outlook in a WinXP VM 
 +would open the page in the host Linux's browser. (Yes, VMware Fusion can do 
 +that via VMwareOpenHost.exe, but VMware Player doesn't seem to want to do 
 +that, so this was written.)
 +
 +WINDOWS-SIDE INSTALLATION
 +=========================
 +
 +    1. Change ``giHOST`` to match your server-side hostname
 +    2. Call this script with --install
 +
 +LINUX-SIDE INSTALLATION
 +=======================
 +
 +    1. Run the script without arguments
 +
 +TODO: Use Python-Win32 modules to implement a Win32 DDE server to catch 
 +special invocations, such as "start http://example.org"
 +
 +TCP/IP PROTOCOL
 +===============
 +
 +The protocol uses endpoint readiness to signal when processing has been 
 +completed. This relies on the behaviour of ``recv()``, which blocks until data 
 +is available (returns a non-empty string) or the local READ endpoint has been 
 +closed by the remote end (returns an empty string).
 +
 +    1. Client:
 +
 +        a. Connects to server
 +        b. Transmits URL data as ASCII-encoded text
 +        c. Closes WRITE end-point
 +        d. Starts spinning on recv()
 +
 +    2. Server:
 +
 +        a. Waits for a connection
 +        b. Spins on recv() until it returns an empty string
 +        c. Closes WRITE end-point
 +        d. Spins on recv()
 +        e. Closes connection
 +
 +    3. Client:
 +
 +        a. Finishes spinning on recv()
 +        b. Closes connection.
 +"""
 +__docformat__ = "restructuredtext en"
 +
 +giPORT = 43233  # That's IE2FF in T9 (predictive text, as on a phone)
 +giHOST = "e102928-lin"
 +
 +# -----------------------------------------------------------------------------
 +def regedit(rRegistryFragment):
 +    import os
 +    import tempfile
 +
 +    import subprocess as sp
 +
 +    assert os.name == "nt", "You're not running Windows!"
 +
 +    rRegistryFragment = os.linesep.join( rRegistryFragment.splitlines() )
 +
 +    rTF = tempfile.mktemp()
 +
 +    try:
 +        with file(rTF, "wb") as sTF:
 +            sTF.write( rRegistryFragment.encode("utf-16") )
 +            sTF.flush()
 +
 +        # Seems we must close the file or regedit cannot read it. Go figure.
 +
 +        sPH = sp.Popen([
 +            "regedit",
 +            "/S",   # Silent
 +            sTF.name])
 +
 +        iRetVal = sPH.wait()
 +
 +    finally:
 +        if os.path.exists(rTF):
 +            os.unlink(rTF)
 +
 +    return iRetVal == 0
 +
 +# -----------------------------------------------------------------------------
 +def install():
 +    import os
 +    import sys
 +    from textwrap import dedent
 +
 +    # Note that backslashes have to be escaped, and double-escaped between a 
 +    # drive letter and a path.
 +
 +    rRegistryFragment = dedent(R"""
 +    Windows Registry Editor Version 5.00
 +
 +    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\iexplore.exe]
 +    "Debugger"="%s %s"
 +
 +    """).lstrip() % (
 +            (os.path.abspath( sys.executable )
 +                .replace(":\\", ":\\\\")
 +                .replace("\\", "\\\\")),
 +
 +            (os.path.abspath( install.func_code.co_filename )
 +                .replace(":\\", ":\\\\")
 +                .replace("\\", "\\\\")),
 +            )
 +
 +    if regedit(rRegistryFragment):
 +        print "Installation was successful"
 +    else:
 +        print "Installation failed, `regedit.exe` returned %d" % iRetVal
 +
 +# -----------------------------------------------------------------------------
 +def uninstall():
 +    from textwrap import dedent
 +
 +    # Note that backslashes have to be escaped, and double-escaped between a 
 +    # drive letter and a path.
 +
 +    rRegistryFragment = dedent(R"""
 +    Windows Registry Editor Version 5.00
 +
 +    [-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\iexplore.exe]
 +
 +    """).lstrip()
 +
 +    if regedit(rRegistryFragment):
 +        print "Uninstallation was successful"
 +    else:
 +        print "Uninstallation failed, `regedit.exe` returned %d" % iRetVal
 +
 +# -----------------------------------------------------------------------------
 +def server():
 +    """
 +    Launch URLs sent via TCP/IP using ``gnome-open``.
 +    """
 +    import socket
 +    import subprocess as sp
 +
 +    sSock = socket.socket()
 +    sSock.bind( ("", giPORT) )
 +    sSock.listen(1)
 +
 +    print "Listening on", giPORT
 +
 +    while True:
 +        sConn, tAddr = sSock.accept()
 +
 +        rMessage = ""
 +        while True:
 +            rData = sConn.recv(1024)
 +            if rData == "":
 +                break
 +            rMessage += rData
 +
 +        sConn.shutdown( socket.SHUT_WR )     # Indicate finished
 +
 +        # Spin until remote side is also finished
 +        while sConn.recv(1024) != "":
 +            pass
 +
 +        sConn.close()
 +
 +        print rMessage
 +
 +        sPH = sp.Popen([
 +            "gnome-open",
 +            rMessage])
 +
 +        sPH.wait()
 +
 +# -----------------------------------------------------------------------------
 +def client():
 +    R"""
 +    ``sys.argv`` should look like so:
 +
 +        0. ``H:\IE2FF.py``
 +        1. ``C:\Program Files\Internet Explorer\IEXPLORE.EXE``
 +        2. May be absent. If present, should be one of:
 +
 +            a. ``-nofile``, indicates DDE usage (TODO)
 +            b. ``http://...`` (or other URL)
 +    """
 +    import sys
 +
 +    if len(sys.argv) < 3 or sys.argv[2] == "-nofile":
 +        # TODO: Implement fallback behaviour (start local browser?)
 +        return
 +
 +    rMessage = sys.argv[2]
 +
 +    import socket
 +    import subprocess as sp
 +
 +    sConn = socket.socket()
 +    sConn.connect( (giHOST, giPORT) )
 +    sConn.sendall( rMessage )
 +    sConn.shutdown( socket.SHUT_WR )    # Indicate finished
 +
 +    # Spin until remote side is also finished
 +    while sConn.recv(1024) != "":
 +        pass
 +
 +    sConn.close()
 +
 +# -----------------------------------------------------------------------------
 +def main():
 +    import platform
 +    from optparse import OptionParser
 +
 +    sParser = OptionParser(
 +            description=" ".join(
 +                x.strip() for x in
 +                """\
 +                This script catches URL clicks (actually iexplore.exe 
 +                invocations) on a Windows machine and forwards them over 
 +                TCP/IP to a Linux machine (also running this script) which 
 +                launches them in the default browser (e.g. Firefox).
 +                """.splitlines()
 +            )
 +        )
 +
 +    sParser.add_option(
 +        "--install",
 +        action="store_true",
 +        dest="yInstall",
 +        help="Intercept all invocations of iexplore.exe. Internet Explorer "\
 +             "will not be available until --uninstall is used.",
 +        default=False)
 +
 +    sParser.add_option(
 +        "--uninstall",
 +        action="store_true",
 +        dest="yUninstall",
 +        help="Disable interception of iexplore.exe. Internet Explorer will "\
 +             "be available again.",
 +        default=False)
 +
 +    # Parse command line
 +    sOptions, lArgs = sParser.parse_args()
 +
 +    if sOptions.yInstall:
 +        install()
 +
 +    if sOptions.yUninstall:
 +        uninstall()
 +
 +    if platform.system() == "Linux":
 +        server()
 +    else:
 +        client()
 +
 +# -----------------------------------------------------------------------------
 +if __name__ == "__main__":
 +    main()
 +</code>
 +
  
 ===== BASH shell ===== ===== BASH shell =====
coding/utilities.1217507897.txt.gz · Last modified: 2011/03/01 16:19 (external edit)